Customizing a subnet
Tutorial to add a new syscall to Filecoin Virtual Machine and create a new built-in actor in IPC to activate the syscall
Last updated
Tutorial to add a new syscall to Filecoin Virtual Machine and create a new built-in actor in IPC to activate the syscall
Last updated
IPC is uniquely hyper customizable as a scalability framework. Subnets are highly customizable and can be temporal, allowing subnet operators to spin up customized subnets for various needs, including modular consensus, gas option, configurable chain primitives, customized features vis pluggable syscalls and build-in actor.
In this tutorial, we will focus on how to extend features to your IPC subnet by customizing syscalls that are 'pluggable' as needed.
IPC uses the as its execution layer, which is a WASM-based polyglot VM. FVM exposes all system features and information through syscalls, as part of its SDK. The FVM SDK is designed to be pluggable to enable user-defined custom features with syscalls, while implementing default features from FVM kernel. Use cases includes:
Extending chain-specific syscalls once IPC supports more root chains. Because other chains may have their own special syscalls different as Filecoin (proof validation, etc.).
Extending features to support better development tools. E.g. adding special debugging syscalls, adding randomness syscalls, and supporting more ECC curve, etc.
implementation
Rust
These instructions describe the steps required to create a new kernel which implements a new syscall along with an example built-in actor that shows how you would call that syscall. Full example .
In this example, we will be creating a simple syscall which accesses the filesystem. Inside syscalls, you can run external processes, link to rust libraries, access network, call other syscalls, etc.
We’ll call this new syscall my_custom_syscall
and its defined as follows:
Define a struct CustomKernelImpl
which extends DefaultKernel
. We use the ambassador
crate to automatically delegate calls which reduces the boilerplate code we need to write. Here we simply delegate all calls to existing syscall to the DefaultKernel
.
Implement my_custom_syscall
Here is where we implement our custom syscall:
Next we need to implement the Kernel
trait for the new CustomKernelImpl
. You can treat this as boilerplate code and you can just copy it as is:
Next we need to implement the SyscallHandler
trait for the CustomKernelImpl
and link all the syscalls to that kernel. We need to explicitly list each of the syscall traits (ActorOps, SendOps, etc) manually here in addition to the CustomKernel
trait. Then inside the link_syscalls
method we plug in the actor invocation to the kernel function that should process that syscall. We can link all the existing syscalls using the link_syscalls
on the DefaultKernel
and then link our custom syscall.
Once this function is linked to a syscall and exposed publicly, we can use this syscall by calling my_custom_kernel.my_custom_syscall
Since the customized syscall is implemented in a CustomKernelImpl
which extends and implements all the behaviors for DefaultKernel
, we can plug it into IPC instead of DefaultKernel
\
To use this kernel in fendermint code, replace DefaultKernel
with CustomKernelImpl
for the executor
declaration in fendermint/vm/interpreter/src/fvm/state/exec.rs
Now, we are all set to use the custom syscall in the IPC subnet. The custom syscall can be called in IPC actors to utilize the extended feature. For this tutorial, we can create a simple actor to demonstrate how to import and call the custom syscall and then confirm that its working correctly.
We have so far created a new kernel and syscall, switched IPC to use that kernel and created an actor which calls the new syscall. However, in order to call this actor in IPC, we must load it from the custom_actors_bundle.
To do this open fendermint/vm/interpreter/src/fvm/genesis.rs
file and in the init
function add our customsyscall actor right after creating the chainmetadata
actor:
Your actor has now been deployed and we should be able to send it messages!
In the last step in this tutorial we will send our customsyscall actor messages which will cause it to run its Invoke method and execute the custom syscall. Here, we will simply call it for every new block height. Go to fendermint/vm/interpreter/src/fvm/exec.rs
and inside the begin
function add the following code:
This code sends a message to the customsyscall
actor and parses it output after it has been executed. We print out the return value from the actor, which will be the return value of our custom syscall.
In order to see this working end to end in IPC, you can run one of our integration tests. These tests run IPC in docker containers so make sure to have docker installed on your machine if you are following along.
We must first need to build a new docker container for the fendermint image which will contain all the code you have added so for. To do this run:
After the fendermint docker image has been built, you can run one of the integration tests
View fendermint logs and see the output generated by calling the customsyscall
actor in each epoch:
View the docker logs:
You can now run cargo make teardown
to stop the containers.
Let’s create a customsyscall
folder in ipc/fendermint/actors/
and then create a file called in that new folder. Here we want to create a very simple actor, which when invoked (received a message on its Invoke method) will call the new syscall and return its value:
Even though this is Rust code, IPC will compile it as a Wasm target and then run the compiled Wasm code inside FVM as an actor. However, we want to share some of the code between Wasm and IPC, such as the actor name CUSTOMSYSCALL_ACTOR_NAME
and the Invoke
method enum. We will define these in a separate file called as follows:
We next need to write a file which exports the shared code and only compiles actor.rs
if we are building the Wasm actor.
NOTE: There are several other files you need to change to compile this actor and package it with the other actors that IPC uses. Please refer to the full example for the following other files you need to change: