Skip to content

prototype minimal Wasm actor deployment flow #444

Closed
@raulk

Description

@raulk

Context

Having a minimal, experimental protoype of an actor deployment flow will unlock several downstream community projects. What's described here is most certainly not the definitive flow, but it's doubly useful:

  • It's a sufficiently functional PoC to allow FVM devs to spin up devnets, and node operators to provide testnets, where actors can be deployed.
  • Can be regarded like a spike to explore the problem and dissipate unknowns.

This implementation should sit in a branch, ideally behind a Cargo feature flag, and should carry prominent EXPERIMENTAL warnings.

InitActor enhancements

See https://github.com/filecoin-project/FIPs/blob/master/FIPS/fip-0030.md#actor-deployment for reference.

State object

Add an actor_registry: Hamt<Cid, ActorSpec> field to the state object, where:

struct ActorSpec {
    // The actor that installed this actor.
    creator: ActorID,
    // The originator of the message that triggered creator to install this actor.
    // Probably needs https://github.com/filecoin-project/ref-fvm/issues/300
    originator: ActorID,
    // The version of the invocation container.
    container_version: u32,
}

Operations

Add an InstallActor(bytecode: RawBytes) -> Result<InstallActorReturn, ActorError> method, where:

struct InstallActorReturn {
    // The CodeCID with which this actor can be constructed.
    code_cid: Cid,
    // Whether the bytecode was effectively installed in this call or not.
    // False when the CodeCID already existed.
    // Alternatively we could fail, but that would break API idempotency.
    installed: bool,
}

This method:

  1. Computes the Cid of the parameter block (Wasm bytecode).
  2. Checks if an entry already exists inactor_registry. If yes, it shortcircuits and returns the CodeCID and installed=false.
  3. Adds the bytecode to the blockstore.
  4. Calls the actor::install_actor(block_id) -> Result<Cid> syscall to apply the installation. Aborts on failure.
  5. Adds an entry in actor_registry, filling in the active container version, creator, and originator.
  6. Returns the CodeCID and installed=true

ref-fvm enhancements

actor::install_actor syscall

  1. Persists the Wasm bytecode to the blockstore, and remembers the resulting Cid as the code_cid.
  2. Charge the actor installation gas defined in FIP: gas model adjustment for user programmability. FIPs#317. (Can be 0 for now)
  3. Calls kernel.call_manager().machine().engine().preload(blockstore, code_cid) => this compiles the bytecode and caches the instantiated module in memory (cache will be entirely revisited for M2).

In the future, this will perform bytecode validation, structural analysis to derive complexity factors, patching to replace floating point operations, and more.

Note: this approach leaks cached modules in case of reorgs.

Caveats

  • There are message payload limits in various components and protocols that hinder the inlining of Wasm bytecode in chain messages. Gossipsub: 1MiB, Bitswap: 2MiB (suspected), Mempool: 64KiB. The effective limit is the lowest one (64KiB), which most certainly will always be insufficient. We need to figure out a path forward (e.g. offloading and chunking), but for this PoC it would be acceptable to increase these limits.
  • Did I say this is EXPERIMENTAL and will change in many ways? If you depend on this flow, your code will be broken in the future.

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

Relationships

None yet

Development

No branches or pull requests

Issue actions