Setup, build and start the testnet with:
just
You should see this with clickable links to PJS:
Things that came up and need adressing:
- DMP delivery fee increases once the relay starts spamming
- AH can silently ignore messages if they are too big. Need to safeguard against this on the relay side already.
The test setup is quite convoluted, due to two missing dependencies:
- ZombieBite: This would allow to easily fork the network with live state.
- Runtime stable2409: This would hopefully make it possible to build the runtime without all the current hacks.
This results in two short-comings:
- The AssetHub initial state is empty. Therefore not having realistic PoV on the parachain side.
- The build-setup is complicated and relies on scripts to patchup and copy files - just to make cargo happy.
This results in the following structure after running the just
command:
justfile
: Central manager script with sub-commands- (no cmd): Setup, build and spawn the network.
build
: Build the code.spawn
: Spawn the network without building.
runtimes
: Runtimes Polkadot runtimes from the 1.3.3 release.polkadot-sdk-1.14
: Local development folder for editing SDK pallet. If you need to modify a pallet, do it there. Branch isoty-ahm-controller
.polkadot-sdk
: Don't modify this. Just used to build the nodes.vendor
: The dependencies that the runtime builds against.
The code in the runtimes
directory relies on crates-io.patch
entries in its Cargo.toml
file to use the dependencies from the vendor
directory instead of from crates.io
directly. This is needed to allow us to build against modified versions of the dependencies. The preferred way of doing this - using the 1.14 branch of the SDK - does not work here, since that branch is out of sync with crates.io
.
This means that any modification a developer does to a pallet, for example in polkadot-sdk-1.14/substrate/frame/balances
, will be copied by the justfile
to the vendor
directory. This works fine for normal code changes, but for changes to the Cargo.toml
, it neccecitates an entry in vendor-dep.patch
. This patch will always be applied before building.
Hopefully this graph helps to understand the relation:
The overall migration is coordinated by the ahm-controller
pallet that is deployed on both Relay and AH. The controller pallet calls into each pallet one-by-one and ensures that they finish their migration.
The linear data-flow looks like this:
Relay on_init
-> ahm-controller::relay_init
-> pallet-balances::migrate_out
-> XMCP
-> Ah on_init
-> message_queue::process
-> pallet-balances::migrate_in
.
And in graphical form:
Pallets can generally be migrated in two patterns. Both patters are demonstrated for a single pallet.
The pallet itself is changed to include a new config item, possibly a AhReserveMigrator
, a new call migrate_in_*
and a public function migrate_out_
that can be called by the AHM controller pallet. It is demonstrated in pallet-indices
.
This approach makes sense when the pallet itself is complex, or the migration needs to call different internal functions of the pallet. Generally, this approach is more messy, as it mandates changes to the pallet.
The only issue with this approach is, that it modifies different crates. When multiple people will work on the AHM, then it could become messy and chaotic to manage.
In this case, no change to the migrated pallet itself is done. Instead, a new module is added to the AHM controller pallet, which corresponds to the pallet name and handles its migration.
This works well when the pallet is simple (aka. has a low number of storage invariants) and the migration will not need to call too many internal functions of the pallet.
Here are some different ways to approach the migration of accounts.
This strategy uses sufficient refs to ensure that no account will be dusted on either side and both exist during the time of operation.
We need to be careful to not mess up references that other pallet have placed, but the only pallet using this kind is the assets
pallet, which can easily be reviewed for conflicts.
Accounts will be migrated in the following way:
- A pallet wants to migrate a specific freeze, lock, reserve or hold. Otherwise nothing happens for that account (as of yet).
- The Relay places a sufficient reference on the account.
- The Relay puts the information that a sufficient was placed into storage.
- The Relay unlocks/unreserves the balance and teleports it over.
- The AH palaces a sufficient reference on the account.
- The AH puts the information that a sufficient was placed into storage.
- The AH locks/reserves/freezes/holds the balance that was teleported.
- At the end of the migration, both Relay and AH cleanup the sufficient refs.
Another way would be to force-teleport the ED of 0.01 DOT to AH for all affected accounts.
Originally I thought this to be a good idea, but some reasons not todo it:
- Has to sometimes mint the ED, in case that accounts have between 1 and 1.01 DOT balance without a reserve or lock.
- Would affect system accounts and possibly violate some of their invariants.