When the runtime is updated we need to ensure that it can handle state data that was written by a previous version of the runtime. Otherwise the old data cannot be accessed. To allow for this I propose the following scheme.
Let’s consider as an example user with just a handle
field that we store on chain. At first we define it as
#[derive(Decode, Encode)]
enum User {
UserV1(UserV1)
}
#[derive(Decode, Encode)]
struct UserV1 {
handle: String
}
Now if we want to add a karma
field to the user we introduce a new version:
#[derive(Decode, Encode)]
enum User {
UserV1(UserV1)
UserV2(UserV2)
}
#[derive(Decode, Encode)]
struct UserV1 {
handle: String
}
#[derive(Decode, Encode)]
struct UserV2 {
handle: String,
karma: u32
}
A User
value encoded with the first version of the code can safely by decoded with the second version of the code and produces the expected result. This is guaranteed by the fact that the SCALE codec uses a byte to indicate which variant is used and that number stays stable if we just add variants.
If the user needs to change again we can another UserV3
variant and struct. Existing variants and structs may never be changed.
I suggest we adopt this as a policy for adding new storage and add it to the developer docs. For existing storage we’ll need to replace it with a new storage declaration if we change it.