Skip to main content

How to customize ArbOS on your Orbit chain

PUBLIC PREVIEW, MAINNET READY

Orbit chains are now Mainnet ready! Note that Orbit is still a public preview capability - the Orbit product and its supporting documentation may change significantly as we capture feedback from readers like you.

To provide feedback, click the Request an update button at the top of this document, join the Arbitrum Discord, or reach out to our team directly by completing this form.

Being able to customize and control every aspect of your chain is one of the key benefits of building with the Arbitrum Orbit tech stack. Performing these customizations, however, is complex and may not be tenable for every team (depending on the type of changes your team is trying to make). 

Due to the complex nature of ArbOS customizations, we strongly recommend being very intentional with your chain's customizations and budget for extra resources to perform the short term work, but also to manage the medium and long term maintenance and security risks. Despite our desire to help every team with their customizations, the Offchain Labs team has limited capacity to review and audit every team's customizations but we will do our best, alongside your RaaS teams, to support you in any way we can.

In which case you need to customize ArbOS upgrade

First, when you make changes to your nitro code and it may affect State Transition Function (You can refer to Customize STF),

Second, if your Orbit Chain is not started for the first time but the changes are made while it is running.

If your changes meet both those 2 points, then you need to customize the ArbOS upgrade.

Also, if you added some changes to the chain and want to upgrade them at some time in the future. You should also take it into ArbOS upgrade process.

Here we will provide you 4 examples that need to add ArbOS Upgrade related code:

1. Add a new method to exsiting precompile on a specific ArbOS version:

After you add sayHi() to ArbSys.go according to the guide in customize precompile option 1, you need continue to modify precompile.go.

For example, the original code is

ArbSys := insert(MakePrecompile(pgen.ArbSysMetaData, &ArbSys{Address: types.ArbSysAddress}))
arbos.ArbSysAddress = ArbSys.address
arbos.L2ToL1TransactionEventID = ArbSys.events["L2ToL1Transaction"].template.ID
arbos.L2ToL1TxEventID = ArbSys.events["L2ToL1Tx"].template.ID

You need to write after it

ArbSys := insert(MakePrecompile(pgen.ArbSysMetaData, &ArbSys{Address: types.ArbSysAddress}))
arbos.ArbSysAddress = ArbSys.address
arbos.L2ToL1TransactionEventID = ArbSys.events["L2ToL1Transaction"].template.ID
arbos.L2ToL1TxEventID = ArbSys.events["L2ToL1Tx"].template.ID
// The arbos version control logic
ArbOwner.methodsByName["SayHi"].arbosVersion = ${The arbos version you want to activate this method}

In this way, this method will be executed normally and return results only after you update ArbOS to the target version.

2. Create a new precompile contract on a specific ArbOS version

After you add a new precompile named ArbHi according to the guide in customize precompile option 2 and make changes to precompile.go, you also need to make the following changes:

ArbHi := insert(MakePrecompile(pgen.ArbHiMetaData, &ArbHi{Address: types.ArbHiAddress})) // types.ArbHiAddress here is an example address
// Set activate version to the precompile
ArbHi.arbosVersion = ${The arbos version you want to activate this precompile}
// Set activate version to all method
for _, method := range ArbHi.methods {
method.arbosVersion = ${The arbos version you want to activate this precompile}
}

In this way, ArbHi and all its methods will be activated after the ArbOS version you set.

3. Create a new ArbOS state on a specific ArbOS version

After you add a new state myNumber according to the guide in customize precompile Option 5, you also need to rewrite UpgradeArbosVersion in arbosstate.go: Add your expected ArbOS version to the switch case statement of nextArbosVersion. Here we will take ArbOS V21 as an example:

ensure := func(err error) {
if err != nil {
message := fmt.Sprintf(
"Failed to upgrade ArbOS version %v to version %v: %v",
state.arbosVersion, state.arbosVersion+1, err,
)
panic(message)
}
}
nextArbosVersion := state.arbosVersion + 1
switch nextArbosVersion {
case 1:
//.....
case 2:
//....
//.....
case 21:
// Set your new ArbOS state value here
ensure(state.SetNewMyNumber(${random number}))
//....
}

Here, we will ensure that the initial value of $(an random number) after ArbOS is upgraded to V21.

caution

It should be noted that when you initialize the state (initial code is in customize precompile Option 5), you need to initialize it to 0 or null value first to avoid potential blockchain reorg.

And, please make sure that your program cannot call the state.SetNewMyNumber or other function might change the value of myNumber before ArbOS V21. To prevent this, if you are using an external call to the precompile contract to change the value, you can refer to point 1 or point 2 to set the activation time of the precompile contract method. If your nitro code needs to call this method to change the state, you can continue reading point 4.

4. Any changes in the STF logic that will affect the final execution result

If you change the logic in STF and it will cause the execution result of the transaction to be different, you need to keep the original execution logic and put the new logic into another branch. You can use if else statement to control it.

For example, we change the SayHi return after upgrade the ArbOS version:

// The method in ArbHi precompile
func (con *ArbHi) SayHi(c ctx, evm mech) (string, error) {
if p.state.ArbOSVersion() >= ${The arbos you want to upgrade to} {
// Your new logic code
return "hi, new ArbOS version", nil
} else {
// The old logic code needs to be kept
return "hi", nil
}
}

In this example, we use precompiles as example, some logic might also affect stf such as the methods in block_process.go, internal_tx.go, tx_processor.go and so on. You need use those arbos control ways to different version of logic as well.

Schedule ArbOS upgrade

After you add ArbOS version control to the nitro code, you can update ArbOS. You can refer to the document ArbOS upgrade to upgrade. It should be noted that if you set a higher ArbOS version as the upgrade target, all the features added between the current version and the target version will be activated. For example, if your current version is ArbOS v18 and you set the target version to v25, then all the features between v18 and v25 will be loaded.

Upgrade WASM Module Root on parent chain

Afterwards, since Arbitrum might need to make validation and fraud proofs on the parent chain, you need to update the Wasm Module Root recorded on the parent chain. Please continue reading customize stf for follow-up operations.