Install opengov-cli

cargo install --locked --force --git https://github.com/joepetrowski/opengov-cli
opengov-cli 

Note: if you already have opengov-cli installed you'll need to update to get the changes from opengov-cli#34

Enactment times

We'll schedule these to enact first on Kusama, then on Polkadot a week later. Both scheduled times will be morning UTC on a weekday when most engineers are online. Kusama runtime upgrades usually confirm in about 7 days, Polkadot more like 9 or 10 depending on backing. I'm posting them both on 20250210 (a Monday), so Kusama should be scheduled for 9 days and Polkadot 16 days from now (20250219 and 20250226 respectively). Grabbing some block numbers to make this coincide with roughly 8am UTC on these days gives us:
Kusama enactment block: 27155056
Polkadot enactment block: 24899075

Upgrade Kusama to v1.4.0

https://github.com/polkadot-fellows/runtimes/releases/tag/v1.4.0

Create ref

Build upgrade

❯ opengov-cli build-upgrade --network kusama --relay-version v1.4.0

Downloading runtimes.

Downloading... kusama_runtime-v1004000.compact.compressed.wasm
Downloading... asset-hub-kusama_runtime-v1004000.compact.compressed.wasm
Downloading... encointer-kusama_runtime-v1004000.compact.compressed.wasm
Downloading... bridge-hub-kusama_runtime-v1004000.compact.compressed.wasm
Downloading... people-kusama_runtime-v1004000.compact.compressed.wasm
Downloading... coretime-kusama_runtime-v1004000.compact.compressed.wasm

Generating parachain authorization calls. The runtime hashes are logged if you would like to verify them with srtool.

Kusama Asset Hub Runtime Hash:   0x04915337fde3497621c5caa36cacd94c53bfda3fc7089cfaf18bfd1510b95d18
Kusama Encointer Runtime Hash:   0x35f406c64afd06508e9d86edbfa33abd3bbd748dbc0c6640baa3e6c6a4dd37a0
Kusama Bridge Hub Runtime Hash:  0xbdad0af3745ff7d17776b51e29c261290ea72e7d4c65140300d199ba8ee50deb
Kusama People Runtime Hash:      0x3ca7ebbfc8fafec59a1f0559227b96d31a5f00964c46d388ee17f6fadd5b39cf
Kusama Coretime Runtime Hash:    0x766d1d6ab828473defb23986d05c4410ed5035042be48bc1f6ccd41b4020ac0f

Generating Relay Chain upgrade call. The runtime hash is logged if you would like to verify it with srtool.

Kusama Relay Chain Runtime Hash: 0xa5b7291bd5984a80f8819c3af0030d484c2af5a78ea4cd9b8422681ea81ff4e7

Batching calls.

Success! The call data was written to ./upgrade-kusama-1.4.0/kusama-1.4.0.call
To submit this as a referendum in OpenGov, run:

opengov-cli submit-referendum \
    --proposal "./upgrade-kusama-1.4.0/kusama-1.4.0.call" \
    --network "kusama" --track <"root" or "whitelistedcaller">

Generate referendum calls

❯ opengov-cli submit-referendum --at 27155056 \
                --proposal "./upgrade-kusama-1.4.0/kusama-1.4.0.call" \
                --network "kusama" --track "whitelistedcaller"

Submit the preimage for the Fellowship referendum:
https://polkadot.js.org/apps/?rpc=wss%3A%2F%2Fkusama-rpc.dwellir.com#/extrinsics/decode/0x2000882c00740edba4531f2695dc8762141c48fa857efaded3f126e67e1d912a80b64e42fb

Open a Fellowship referendum to whitelist the call:
https://polkadot.js.org/apps/?rpc=wss%3A%2F%2Fkusama-rpc.dwellir.com#/extrinsics/decode/0x17002b0f02b0d94fdc83d6a0d4812da1d774fd1d7d3ffae85b0dacb9fd14a8ce61b17bf64722000000010a000000

Submit the preimage for the public referendum:
https://polkadot.js.org/apps/?rpc=wss%3A%2F%2Fkusama-rpc.dwellir.com#/extrinsics/decode/0x200001052c03180418630004000100a10f04082f000006024247c139011088000904915337fde3497621c5caa36cacd94c53bfda3fc7089cfaf18bfd1510b95d18630004000100a50f04082f000006020300943577012088000935f406c64afd06508e9d86edbfa33abd3bbd748dbc0c6640baa3e6c6a4dd37a0630004000100a90f04082f000006028200493b0110880009bdad0af3745ff7d17776b51e29c261290ea72e7d4c65140300d199ba8ee50deb630004000100b10f04082f0000060282f4563901108800093ca7ebbfc8fafec59a1f0559227b96d31a5f00964c46d388ee17f6fadd5b39cf630004000100b50f04082f0000060242456e390110880009766d1d6ab828473defb23986d05c4410ed5035042be48bc1f6ccd41b4020ac0f0009a5b7291bd5984a80f8819c3af0030d484c2af5a78ea4cd9b8422681ea81ff4e7

Open a public referendum to dispatch the call:
https://polkadot.js.org/apps/?rpc=wss%3A%2F%2Fkusama-rpc.dwellir.com#/extrinsics/decode/0x15002b0d0272282a8971a9df79ef27ebebf9a4bff4499df9f7657deaf286dc4b8aa19fcc994001000000705a9e01

Batch to submit on Kusama Relay Chain:
https://polkadot.js.org/apps/?rpc=wss%3A%2F%2Fkusama-rpc.dwellir.com#/extrinsics/decode/0x1804102000882c00740edba4531f2695dc8762141c48fa857efaded3f126e67e1d912a80b64e42fb17002b0f02b0d94fdc83d6a0d4812da1d774fd1d7d3ffae85b0dacb9fd14a8ce61b17bf64722000000010a000000200001052c03180418630004000100a10f04082f000006024247c139011088000904915337fde3497621c5caa36cacd94c53bfda3fc7089cfaf18bfd1510b95d18630004000100a50f04082f000006020300943577012088000935f406c64afd06508e9d86edbfa33abd3bbd748dbc0c6640baa3e6c6a4dd37a0630004000100a90f04082f000006028200493b0110880009bdad0af3745ff7d17776b51e29c261290ea72e7d4c65140300d199ba8ee50deb630004000100b10f04082f0000060282f4563901108800093ca7ebbfc8fafec59a1f0559227b96d31a5f00964c46d388ee17f6fadd5b39cf630004000100b50f04082f0000060242456e390110880009766d1d6ab828473defb23986d05c4410ed5035042be48bc1f6ccd41b4020ac0f0009a5b7291bd5984a80f8819c3af0030d484c2af5a78ea4cd9b8422681ea81ff4e715002b0d0272282a8971a9df79ef27ebebf9a4bff4499df9f7657deaf286dc4b8aa19fcc994001000000705a9e01

Test ref

We can fork the network with chopsticks and check that the XCMs are sent and that we can upgrade the chains without error.

npx @acala-network/chopsticks@latest xcm -r kusama -p kusama-asset-hub -p encointer-kusama -p kusama-bridge-hub -p kusama-people -p kusama-coretime

Submit the preimage for the referendum on localhost:8005 (kusama relay) using the call from opengov-cli

Screenshot 2025-02-10 at 12.25.28

whitelist the call from the fellows origin using the same call output by opengov-cli in the js window:

// Grab the block number of the current head
// api is already imported, no need to add anything but the following.
const number = (await api.rpc.chain.getHeader()).number.toNumber()

// use chopsticks dev_setStorage to inject the call into the scheduler state for the next block.
await api.rpc('dev_setStorage', {
  scheduler: {
    agenda: [
      [
        [number + 1], [
          {
            call: {
              Inline: '0x2c00740edba4531f2695dc8762141c48fa857efaded3f126e67e1d912a80b64e42fb'
            },
            origin: {
              Origins: 'Fellows'
            }
          }
        ]
      ]
    ]
  }
})
// Make a block to include the extrinsic
await api.rpc('dev_newBlock', { count: 1 })

dispatch the referendum call manually from the whitelistedcaller origin in the js window:

// Grab the block number of the current head
// api is already imported, no need to add anything but the following.
const number = (await api.rpc.chain.getHeader()).number.toNumber()

// use chopsticks dev_setStorage to inject the call into the scheduler state for the next block. The value of `Inline` is just the call data. Crucially with this call we can set the origin to `Root`
await api.rpc('dev_setStorage', {
  scheduler: {
    agenda: [
      [
        [number + 1], [
          {
            call: {
              Lookup: {
                hash: '0x72282a8971a9df79ef27ebebf9a4bff4499df9f7657deaf286dc4b8aa19fcc99',
                len: 320
              }
            },
            origin: {
              Origins: 'WhitelistedCaller'
            }
          }
        ]
      ]
    ]
  }
})
// Make a block to include the extrinsic
await api.rpc('dev_newBlock', { count: 1 })

Then go through each chain (available at 800n) with n in [0,5] and compare its system->authorizedUpgrade hash in state to the hash for each runtime in the fellows release. You should be able to upload the wasm for each chain with the system->applyAuthorizedUpgrade

Upgrade Polkadot to v1.4.0

https://github.com/polkadot-fellows/runtimes/releases/tag/v1.4.0

Create ref

Build upgrade calls

opengov-cli build-upgrade --network polkadot --relay-version v1.4.0

This will include all system parachains in the upgrade.

❯ opengov-cli build-upgrade --network polkadot --relay-version v1.4.0

Downloading runtimes.

Downloading... polkadot_runtime-v1004000.compact.compressed.wasm
Downloading... asset-hub-polkadot_runtime-v1004000.compact.compressed.wasm
Downloading... collectives-polkadot_runtime-v1004000.compact.compressed.wasm
Downloading... bridge-hub-polkadot_runtime-v1004000.compact.compressed.wasm
Downloading... people-polkadot_runtime-v1004000.compact.compressed.wasm
Downloading... coretime-polkadot_runtime-v1004000.compact.compressed.wasm

Generating parachain authorization calls. The runtime hashes are logged if you would like to verify them with srtool.

Polkadot Asset Hub Runtime Hash:   0x5627437c6d5af9296b46fc39ffc066ef453fd99bb90c539a739c7e98c8364582
Polkadot Collectives Runtime Hash: 0x313481ebf6228d2950b92345d2c90ef33a84e5b4c571c6986c507dca08fee9d0
Polkadot Bridge Hub Runtime Hash:  0xcd32415306cadec074e05fbf42647a7e9909331bd97dd1e532d8f9f41d688011
Polkadot People Runtime Hash:      0x2e567d68c1913de7292d66827b057c10a2ef8a6aa1e47e316b6cd5e7b4295e85
Polkadot Coretime Runtime Hash:    0x8f84199c39c4ce451af0400bef1b8fd980ec2ab1192093441c55b29ecca2fe32

Generating Relay Chain upgrade call. The runtime hash is logged if you would like to verify it with srtool.

Polkadot Relay Chain Runtime Hash: 0xdad432732e565b785a2ac346c10578fd3331352dfdf4d1ae33ca005fd3f07fe0

Batching calls.

Success! The call data was written to ./upgrade-polkadot-1.4.0/polkadot-1.4.0.call
To submit this as a referendum in OpenGov, run:

opengov-cli submit-referendum \
    --proposal "./upgrade-polkadot-1.4.0/polkadot-1.4.0.call" \
    --network "polkadot" --track <"root" or "whitelistedcaller">

Generate referendum calls

❯ opengov-cli submit-referendum --at 24899075 \
                --proposal "./upgrade-polkadot-1.4.0/polkadot-1.4.0.call" \
                --network "polkadot" --track "whitelistedcaller"

Submit the preimage for the Fellowship referendum:
https://polkadot.js.org/apps/?rpc=wss%3A%2F%2Fpolkadot-collectives-rpc.polkadot.io#/extrinsics/decode/0x2b00d41f0004010004082f0000060342c78b76216f88170023491956e1a07d55bf6fa0ac7a90404bdb2fe16599064d4ccaf82c22f1c72f21

Open a Fellowship referendum to whitelist the call:
https://polkadot.js.org/apps/?rpc=wss%3A%2F%2Fpolkadot-collectives-rpc.polkadot.io#/extrinsics/decode/0x3d003e0202623e4656d33843d987d5dfa54e31f7434f8c85fdea3a06916490fae72787459935000000010a000000

Submit the preimage for the public referendum:
https://polkadot.js.org/apps/?rpc=wss%3A%2F%2Fpolkadot-rpc.dwellir.com#/extrinsics/decode/0x0a00fd0417031a0418630004000100a10f04082f00000602823e213901108800095627437c6d5af9296b46fc39ffc066ef453fd99bb90c539a739c7e98c8364582630004000100a50f04082f0000060202b8203b0110880009313481ebf6228d2950b92345d2c90ef33a84e5b4c571c6986c507dca08fee9d0630004000100a90f04082f0000060202dca3390110880009cd32415306cadec074e05fbf42647a7e9909331bd97dd1e532d8f9f41d688011630004000100b10f04082f0000060242a2143b01108800092e567d68c1913de7292d66827b057c10a2ef8a6aa1e47e316b6cd5e7b4295e85630004000100b50f04082f0000060202e29c3a01108800098f84199c39c4ce451af0400bef1b8fd980ec2ab1192093441c55b29ecca2fe320009dad432732e565b785a2ac346c10578fd3331352dfdf4d1ae33ca005fd3f07fe0

Open a public referendum to dispatch the call:
https://polkadot.js.org/apps/?rpc=wss%3A%2F%2Fpolkadot-rpc.dwellir.com#/extrinsics/decode/0x1500160d021e4765ea1528d5f3e3367133191bc501cc5bf4fbacf9b16704dba45aec6f92753f0100000003ee7b01

Batch to submit on Polkadot Relay Chain:
https://polkadot.js.org/apps/?rpc=wss%3A%2F%2Fpolkadot-rpc.dwellir.com#/extrinsics/decode/0x1a04080a00fd0417031a0418630004000100a10f04082f00000602823e213901108800095627437c6d5af9296b46fc39ffc066ef453fd99bb90c539a739c7e98c8364582630004000100a50f04082f0000060202b8203b0110880009313481ebf6228d2950b92345d2c90ef33a84e5b4c571c6986c507dca08fee9d0630004000100a90f04082f0000060202dca3390110880009cd32415306cadec074e05fbf42647a7e9909331bd97dd1e532d8f9f41d688011630004000100b10f04082f0000060242a2143b01108800092e567d68c1913de7292d66827b057c10a2ef8a6aa1e47e316b6cd5e7b4295e85630004000100b50f04082f0000060202e29c3a01108800098f84199c39c4ce451af0400bef1b8fd980ec2ab1192093441c55b29ecca2fe320009dad432732e565b785a2ac346c10578fd3331352dfdf4d1ae33ca005fd3f07fe01500160d021e4765ea1528d5f3e3367133191bc501cc5bf4fbacf9b16704dba45aec6f92753f0100000003ee7b01

Batch to submit on Polkadot Collectives Chain:
https://polkadot.js.org/apps/?rpc=wss%3A%2F%2Fpolkadot-collectives-rpc.polkadot.io#/extrinsics/decode/0x2804082b00d41f0004010004082f0000060342c78b76216f88170023491956e1a07d55bf6fa0ac7a90404bdb2fe16599064d4ccaf82c22f1c72f213d003e0202623e4656d33843d987d5dfa54e31f7434f8c85fdea3a06916490fae72787459935000000010a000000

Test ref

We can fork the network with chopsticks and check that the XCMs are sent and that we can upgrade the chains without error.

npx @acala-network/chopsticks@latest xcm -r polkadot -p polkadot-asset-hub -p polkadot-collectives -p polkadot-bridge-hub -p polkadot-people -p polkadot-coretime

Submit the preimage for the referendum on localhost:8005 (polkadot relay) using the call from opengov-cli

whitelist the call from the fellows origin using the same call output by opengov-cli in the collectives js window:

// Grab the block number of the current head
// api is already imported, no need to add anything but the following.
const number = (await api.rpc.chain.getHeader()).number.toNumber()

// use chopsticks dev_setStorage to inject the call into the scheduler state for the next block.
await api.rpc('dev_setStorage', {
  scheduler: {
    agenda: [
      [
        [number + 1], [
          {
            call: {
              Inline: '0x2c00740edba4531f2695dc8762141c48fa857efaded3f126e67e1d912a80b64e42fb'
            },
            origin: {
              FellowshipOrigins: 'Fellows'
            }
          }
        ]
      ]
    ]
  }
})
// Make a block to include the extrinsic
await api.rpc('dev_newBlock', { count: 1 })

You can see the events on the relay whitelisting the call and requesting the preimage.

Screenshot 2025-02-10 at 17.16.32

Upload the public referendum preimage from opengov-cli to the relay chain.

Dispatch the referendum call manually from the whitelistedcaller origin in the relay chain js window:

// Grab the block number of the current head
// api is already imported, no need to add anything but the following.
const number = (await api.rpc.chain.getHeader()).number.toNumber()

// use chopsticks dev_setStorage to inject the call into the scheduler state for the next block. The value of `Inline` is just the call data. Crucially with this call we can set the origin to `Root`
await api.rpc('dev_setStorage', {
  scheduler: {
    agenda: [
      [
        [number + 1], [
          {
            call: {
              Lookup: {
                hash: '0x1e4765ea1528d5f3e3367133191bc501cc5bf4fbacf9b16704dba45aec6f9275',
                len: 319
              }
            },
            origin: {
              Origins: 'WhitelistedCaller'
            }
          }
        ]
      ]
    ]
  }
})
// Make a block to include the extrinsic
await api.rpc('dev_newBlock', { count: 1 })

Then go through each chain (available at 800n) with n in [0,5] and compare its system->authorizedUpgrade hash in state to the hash for each runtime in the fellows release. You should be able to upload the wasm for each chain with the system->applyAuthorizedUpgrade