Upgrading a subnet
IPC Upgrades
As IPC evolves, upgrades are necessary to introduce new features, enhance security, improve scalability, and address new challenges. However, it is critical that all upgrades seamlessly transition without causing forks or consensus failures. This ensures that all nodes in the network remain synchronized.
In this document, we describe how IPC achieves full upgradability of all its components and ensures seamless progression of the blockchain network without compromising consensus.
IPC Actor upgrades
The on-chain logic for IPC is implemented in two contracts, the IPC gateway and the subnet actor, as well as an auxiliary contract use for UX purposes, the registry.
The gateway is a singleton actor that lives in every IPC subnet and implements the common logic for IPC. It is responsible for managing the collateral of subnet, enforcing the firewall requirement, and the cross-net interactions.
The subnet actor is a user-defined actor that implements the specific logic of a subnet. This contract is deployed in the parent from which the child subnet wants to be deployed. There is one subnet-actor for each child subnet in the parent.
The subnet registry behaves as a subnet actor factory that offers users a convenient way of deploying instances of the reference implementation of the subnet actor in a network.
The IPC actors are implemented using the diamond pattern to make it easier to upgrade them. The following sections describes how to upgrade each of these actors
Upgrading the Subnet actor
Once you have you deployed your own subnet you might want to make changes to the subnet actor, for example make custom logic changes, add new functionality, fix bugs, etc.
The code for the subnet actor is located in contracts/src/subnet
which you can directly edit to make your changes. Once ready, you run the following steps to upgrade your already deployed subnet actor:
First, you must know your subnet ID which was returned when you created a child subnet (using
ipc-cli subnet create
). Lets say when you created your subnet that your subnet ID was:/r314159/t410fkp4r67rks3ok4bvbn2rjojhkbig2rwvp4nmor5q
We must convert the subnet ID to an ETH address. To do this, visit the Beryx address converter and input the
t410
address in the Filecoin address input, in this example this would bet410fkp4r67rks3ok4bvbn2rjojhkbig2rwvp4nmor5q
. ClickConvert to ETH
and it will compute the Ethereum address as0x53f91f7e2a96dcae06a16ea29724ea0a0da8daaf
.You must set the
RPC_URL
andPRIVATE_KEY
environmental variables to point to your network provider and the private key of the address you want to use for the deployment, respectivelyNow you should be able to upgrade the subnet actor by running the following command (change NETWORK if you have deployed your subnet on another network)
A successfull output looks like:
If you run the make upgrade-sa-diamond
command again, you should see no output which would also confirm that the upgrade has succeeded.
Fendermint upgrades
Fendermint incorporates a builtin UpgradeScheduler
, enabling the execution of hardcoded Upgrade
migrations at predetermined block heights to advance the on-chain state. Fendermint also supports functionality to halt at predetermined halt_height
in order to switch binary versions.
Upgrade scheduler
At the start of processing each block, Fendermint checks the UpgradeScheduler
whether it contains an Upgrade
for that block height. Only a single Upgrade
can be scheduled for each block height. If an upgrade is found to be scheduled, it will execute the migration
function that is associated with that Upgrade
. If the upgrade migration returns an error it will crash the node.
The migration has access to the state_tree
and blockstore
which allows the user to write migrations such as patching state, sending messages, deploying solidity contracts, deploying new WASM actors, etc.
An Upgrade
is defined as follows:
Fields:
chain_id
: The chain id the upgrade should be applied to.block_height
: The block height where the upgrade should be applied to and themigration
function executed.new_app_version
: Indicates a new application protocol version if the upgrade introduces backward-incompatible changes.migration
: The migration function that is executed when applying the upgrade. The migration function is passed theFvmExecState
which gives access to thestate_tree
,block_store
, ability to send messages and more.
Fendermint supports scheduling multiple upgrades through its UpgradeScheduler
API which is defined as follows:
As an example, if we want to create an UpgradeScheduler
with a single Upgrade
, we could write something like:
We have written guides showing several examples of using the UpgradeScheduler API, which you'll find on the sidebar.
Halting at predetermined height
Although the UpgradeScheduler
supports multiple different types of upgrades, it can not support non-state related changes such as upgrading Fendermint dependencies (such as FVM), adding new syscalls, etc.
To support these use cases, Fendermint includes a halt_height
config which when set (is non zero), will halt and exit Fendermint with a specific exit code (2
) once it reaches that block height.
This enables node operators to replace the Fendermint version at a predetermined future block height with a new Fendermint version containing the new upgrade. Optionally, the new version can specify a new Upgrade
at the specified halt_height
in case a state migration is also required.
This ensures that all nodes run the same Fendermint version for every block height which prevents accidental forking or consensus failures.
Instructions
These instructions detail the steps for utilizing the halting mechanism to synchronize Fendermint application switching with newer versions.
NOTE: Node operators should always check the fendermint exit code. If fendermint exits with code 2, which indicates reaching the halting height, disable automatic restarts. Instead, follow steps 4 and 5 in this section.
1. Determine the future halt_height
Node operators collaborate on which future block height should be used as halt_height
. Selecting the halting height is totally up to the operators, but let say for example purposes that the halt_height was agreed to be set to 10000
.
2. Update the halt_height config
Now, each operator needs to edit the Fendermint config (.fendermint/config/default.toml
) and make sure it contains the following line
Note that Fendermint needs to be restarted before the config changes take effect.
3. Wait until halt_height
Once Fendermint reaches the halt_height
, it will exit and log it reached the halting height.
The node operator can check if Fendermint exited due to reaching halting height by checking if its exit code is 2
.
4. Reset the halt_height
We must change the Fendermint halt_height
to 0 (or some future block height if there is another upgrade planned).
5. Start the new Fendermint version
We can now start the new version of Fendermint which contains the upgrade we need.
Last updated