substrate icon indicating copy to clipboard operation
substrate copied to clipboard

Migrations to have per-version storage structs

Open rossbulat opened this issue 2 years ago • 3 comments

It would be useful to be able to have separate structs for storage items at each version of a migration, so we do not need to amend previously run migrations with different struct variations.

@kianenigma has started exploring this with the nomination pool migration at #13019.

Background

When structs of storage items are changed during a migration, it is challenging to reflect the struct's previous state within previous migrations.

This has been apparent with the work on nomination pool commission (#12511) where a commission field has been added to a BondedPoolsInner struct, which is used in the BondedPools storage item. The current solution is to amend previous migrations to the current structure of the storage item in question, and to comment within the migration that <field_name> was introduced in migration v4.

rossbulat avatar Dec 27 '22 03:12 rossbulat

Yes, more or less what has been shown in https://github.com/paritytech/substrate/pull/13019.

kianenigma avatar Jan 15 '23 12:01 kianenigma

can I attempt the issue? @rossbulat @kianenigma

ECJ222 avatar Jan 23 '23 17:01 ECJ222

can I attempt the issue? @rossbulat @kianenigma

Yes sure, no issues my side. I am engaged with some other things & @kianenigma is at the Polkadot Academy. Would be good to see some movement.

rossbulat avatar Jan 24 '23 07:01 rossbulat

can I attempt the issue? @rossbulat @kianenigma

Yes sure, no issues my side. I am engaged with some other things & @kianenigma is at the Polkadot Academy. Would be good to see some movement.

I have a question about the code guidelines @kianenigma created.

I tried building cargo build --release the pr he created and I noticed a few things.

  1. crate::BondedPools::<T>::translate expects a BondedPoolInner struct returned instead of a BondedPoolInnerV1 struct which is being returned. I had thought of 2 approaches to fix this: (i) Explicitly return the BondedPoolInner type when migrating from V0 to V1. (ii) Rename BondedPoolInner Struct to BondedPoolInnerV1 wherever it's referenced to ensure it's coherent.
// ./nomination-pools/src/migration.rs
105. crate::BondedPools::<T>::translate::<BondedPoolInnerV0<T>, _>(|_key, old_value| {
106.    translated.saturating_inc();
107.    Some(old_value.migrate_to_v1()) <- expects a BondedPoolInner struct, which leads to issues when I try to build.
108. });

Please if you know of any reason why this is happening, I will appreciate it. @rossbulat

ECJ222 avatar Jan 31 '23 03:01 ECJ222

Hi @ECJ222, thank you for attempting this. I was experiencing the same issue as you were having.

The problem is, the migration always needs to refer to the current structure of BondedPoolInner, rather than looking back in history and getting the correct structure corresponding to that migration. Like you similarly suggested, I think the only options are:-

  • To prepend the version for all structs in the pallet, and keep deprecated ones around - very nasty.
  • To maintain the migration history by updating them with the current structures, and leave comments of the updates.

With that said, after some investigation I believe @kianenigma has made the call to not go ahead and maintain these migrations. I imagine they will be removed from the codebase shortly. Other pallets have been following this convention already and are only keeping around the latest migration. I can see why this is the case looking at this issue.

rossbulat avatar Feb 03 '23 06:02 rossbulat

No worries @rossbulat, got it.

ECJ222 avatar Feb 04 '23 04:02 ECJ222