-
Notifications
You must be signed in to change notification settings - Fork 140
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Generics and transmutation make replacing Kernel very difficult #1779
Comments
@alexytsu and I will try this out to confirm it works. |
I can see that adding anything dynamic here is going to be a tough slog against the current norms. I'm having a go adding an additional method type parameter to Kernel::send in #1780 |
The |
Though the kernel can now be successfully replaced #1780 without the need for replacing the DefaultExecutor or DefaultCallManager, it is still hard to provide an API for dynamic mock behaviour of the Kernel. The kernel is not long-lived and it's construction is handled by the CallManager so we usually won't have access to inject it with fake data or instruct it to intercept/passthrough certain calls dynamically. |
So, when we built this, we wanted to pass a constructor through. However, we ran into some recursive type issues. An alternative would be dynamic types. Unfortunately, due to some wasmtime restrictions, this would need to be However dynamic types (objects) can't have generic methods. Which... may be fine, actually. The performance will be slightly worse, but none of this should be performance critical... |
Hm. I dug into making this dynamic and... we probably need to make the blockstore dynamic first. We don't have to, but the types get kind of annoying if we don't. |
|
@alexytsu and I are improving tooling for benchmarking and profiling native actors on the FVM (see https://github.com/anorth/fvm-workbench and filecoin-project/builtin-actors#1236). We've run into great difficulty attempting to fake out expensive VM intrinsic operations like proof verification, the
CryptoOps
trait ofKernel
.We can wrap the
DefaultKernel
and delegate most methods...... but this is only effective for the top-level call. During a sub-call, the wrapped
DefaultKernel
specifies a staticSelf
as a type parameter toCallManger::send
. No instance reference is passed (and indeed the kernel later consumes itself).The
Kernel
trait specifies anew()
constructor, and the call manager later uses that to construct a new kernel for the subcall, but it always constructsDefaultKernel
.With reference to some code in the conformance testing package, we tried also wrapping the CallManger so as to specify our own
BenchKernel
asSelf
instead, also replacingwith_transaction
to do a funky transmutation. This also isn't doing the job. When theDefaultCallManager
instantiates a Kernel inside send_resolved it passes itself in. Therefore, when the first Kernel is created, we get aBenchKernel<DefaultCallManager>
rather than aBenchKernel<BenchCallManager>
as needed. It looks like for theBenchCallManager
to intercept this it would need to re-implement that entire call stackCallManager::send -> DefaultCallManager::send_unchecked -> DefaultCallManager::send_resolved
.The conformance testing code also uses a
TestMachine
, we're not yet sure if this is necessary. But big picture, this static type-parameter based structure makes it very difficult to replace the kernel. There's probably some amount of reimplementation of these components that will get us there, but that would introduce huge and fragile coupling to the internals of the FVM.A much simpler way would be for the
Kernel
type parameter toCallManager
be instead a runtime parameter of aKernel
constructor/factory function (removingnew()
from theKernel
trait). It would then be unnecessary to wrap CallManager or anything else. This would involve following a pointer during an internal send, but much less code and complexity (less monomorphised code to build too).The text was updated successfully, but these errors were encountered: