5

Let's say I have a simple/contrived ink contract:

#[ink(storage)
pub struct MyContract {
    a: u8,
    b: u8,
}

Now let's say it's in production and a == 1 and b == 2.

I've done some work and realised that I no longer need a and instead need a new variable in storage, c.

#[ink(storage)
pub struct MyContract {
    a: u8,
    b: u8,
    c: u8,
}

I've compiled the contract and done a set_code_hash() on my production contract. I've also set the c variable to 3.

I now no longer need a in my contract storage, so I remove it. Here's where the problem lies. The contract storage is currently laid out like so:

[1,2,3]
 ^ ^ ^
 a b c

Removing the a field like so:

#[ink(storage)
pub struct MyContract {
    b: u8,
    c: u8,
}

and doing a set_code_hash() leaves the underlying storage unchanged, but the fields shift like so:

[1,2,3]
 ^ ^ 
 b c 

Which is rather frustrating. How can I remove the a variable from the storage too? Something to make the storage become:

[2,3]
 ^ ^ 
 b c 

I've contemplated doing some kind of bit shift on the contract storage by the size of the field being removed, but I have no idea where to start accessing the byte[] for the contract storage!

Further, imagine using complex types where the fields being removed are not at the start. How could that be done? E.g.

#[ink(storage)
pub struct MyContract {
    a: u8,
    b: u8,
    c: u8,
    d: Mapping<AccountId, AccountId>, // <-- let's say I want to remove this field
    e: Vec<u8>,
    f: u128,
    g: Mapping<u8, u8>,
}
1
  • @HCastano we spoke briefly about this at the polkadot decoded conference, what are your thoughts? I've tried setting the storage key (e.g. pub struct MyContract<KEY: StorageKey = ManualKey<0xABCDEF01>>) but that maintains the storage pointing to the same place all the time, not dealing with any migration of the storage data itself. Thanks for any help in advance :)
    – goastler
    Jul 3, 2023 at 16:46

1 Answer 1

2

You should not change the layout of the storage after upgrade. The order and types of the fields has to remain the same. If you want to remove the field a, you can simply rename it to c as the order will still be u8, u8.

You can read more about upgrading storage in ink! here

2
  • Sure, that would work for the example I gave. But in the real world things change and contract storage is included in that. I've read the docs about upgrading storage in ink already.
    – goastler
    Jul 4, 2023 at 15:39
  • How would you tackle this with the more complex case of changing variable types (e.g. u8 to u16) or removing fields entirely?
    – goastler
    Jul 4, 2023 at 15:40

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.