Test Runtime Upgrades
How to test upgrades depending on a runtime upgrade not yet executed.
Overview
A scenario that frequently occurs is that we need to test a Snowbridge-related runtime upgrade that depends on a system parachain upgrade. Runtime upgrades for system parachains can take up to four weeks to execute. If we wait for the system parachain upgrade to complete first before initiating the Snowbridge upgrades, release cycles could take months.
Therefore, it is useful to be able to test system parachain upgrades that have not yet executed and then apply Snowbridge upgrades to ensure everything works.
Steps
In the following scenario, we will simulate execution of the 1.2.0 upgrade: https://github.com/polkadot-fellows/runtimes/releases/tag/v1.2.0.
Install opengov-cli
Build the preimage for the upgrade:
opengov-cli build-upgrade --network polkadot --relay-version 1.2.0 --filename preimage.hex
Convert the preimage from hex to binary
cd upgrade-polkadot-1.2.0
xxd -r -p preimage.hex > preimage.bin
Determine the size of the of preimage, save as
PREIMAGE_SIZE
On Linux:
$ stat -c%s preimage.bin
1567371
$ export PREIMAGE_SIZE=1567371
On Mac:
$ stat -f%z preimage.bin
1567371
$ export PREIMAGE_SIZE=1567371
Compute blake2-256 hash of preimage, save as PREIMAGE_HASH
$ b2sum -l 256 preimage.bin | awk '{print "0x"$1}'
0x15165c85152568b7f523e374ce1a5172f2aa148721d5dae0441f86c201c1a77b4
$ export PREIMAGE_HASH=0x15165c85152568b7f523e374ce1a5172f2aa148721d5dae0441f86c201c1a77b4
Prepend compact-encoded length prefix to preimage, and convert back to hex, save as PREIMAGE_WITH_LENGTH_PREFIX:
use codec::Encode;
use std::fs::File;
fn main() {
let mut file = File::open("preimage.bin")?;
let mut buf: Vec<u8> = Vec::new();
file.read_to_end(&mut buf)?;
let bytes_encoded = buf.encode();
println!("0x{}", hex::encode(bytes_encoded));
}
Create a chopsticks configuration file for the Polkadot relay chain, substituting the values generated previously:
polkadot.yml
endpoint: wss://polkadot-rpc.dwellir.com
mock-signature-host: true
block: ${env.POLKADOT_BLOCK_NUMBER}
db: ./polkadot.sqlite
import-storage:
System:
Account:
- - - 5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY
- providers: 1
data:
free: '10000000000000000000'
ParasDisputes:
$removePrefix: ['disputes'] # those can makes block building super slow
Preimage:
{
PreimageFor:
[[[[PREIMAGE_HASH, PREIMAGE_SIZE]], PREIMAGE_WITH_LENGTH_PREFIX]],
StatusFor:
[[[PREIMAGE_HASH], { Requested: { count: 1, len: PREIMAGE_SIZE } }]],
}
Use these Chopstics config files for AssetHub and BridgeHub
polkadot-asset-hub.yml
endpoint: wss://statemint-rpc.dwellir.com
mock-signature-host: true
block: ${env.POLKADOT_ASSET_HUB_BLOCK_NUMBER}
db: ./assethub.sqlite
import-storage:
System:
Account:
- - - 5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY
- providers: 1
data:
free: 1000000000000000
polkadot-bridge-hub.yml
endpoint: wss://polkadot-bridge-hub-rpc.dwellir.com
mock-signature-host: true
block: ${env.POLKADOT_BRIDGEHUB_BLOCK_NUMBER}
db: ./bridgehub.sqlite
import-storage:
System:
Account:
- - - 5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY
- providers: 1
data:
free: 1000000000000000
Run Chopsticks
yarn start xcm -r polkadot.yml -p polkadot-asset-hub.yml -p polkadot-bridge-hub.yml
A verification step that can be performed to see if the preimage has been added successfully is to check the preimage
storage in the chain state. The authorized preimage should be in the list of added preimages.
Execute the upgrade on the relay chain using Polkadot-JS:
const number = (await api.rpc.chain.getHeader()).number.toNumber()
await api.rpc('dev_setStorage', {
Scheduler: {
Agenda: [
[
[number + 1],
[
{
call: {
Lookup: {
hash: PREIMAGE_HASH,
len: PREIMAGE_SIZE,
},
},
origin: {
system: 'Root',
},
},
],
],
],
},
})
await api.rpc('dev_newBlock', { count: 1 })
Advance a few blocks on the relay chain
await api.rpc('dev_newBlock', { count: 2 })
Advance by one block on bridgehub (not sure if necessary, need to experiment)
await api.rpc('dev_newBlock', { count: 1 })
Now that the upgrade has been authorized on BridgeHub, we can execute the upgrade by calling parachainSystem.enactAuthorizedUpgrade, passing the parachain WASM blob previously generated by opengov-cli:
Advance a few blocks on both bridgehub AND the relay chain
await api.rpc('dev_newBlock', { count: 1 })
The parachain should now be upgraded.
Caveats
Some polkadot API endpoints aggressively timeout connections, causing Chopsticks to die: Comment
API-WS: disconnected from wss://polkadot-rpc.dwellir.com: 1006:: Abnormal Closure
The usual remedy is to restart chopsticks and pray the API connections don't die again.
Last updated