-
Notifications
You must be signed in to change notification settings - Fork 182
Versioned state for on-chain upgrades #233
Description
Currently, every time an on-chain data structure changes, a state migration needs to be run to migrate all state from the old format to the new format.
- As the state-tree grows, this becomes more and more time consuming and difficult.
- In a future world with a VM, it would be nice to perform upgrades through normal chain mechanisms. But there's no way this can happen if all state needs to be migrated up-front (won't happen in a single block time).
There's a pretty simple solution: version the state. However, there are two options:
- Version entire actor states.
- Version each object separately (e.g., each sector info).
Versioned Actor State
This is the cleanest solution as migrations are atomic. Unfortunately, this would still force us to eventually migrate the entire actor's state as a whole, and that can get pretty expensive (e.g., if we need to migrate all sector infos).
Implementation wise, we'd:
- Keep some version and/or a schema CID inside the actor's metadata.
- If the actor's state version/schema differs from the expected version/schema, require that some client submit a "migrate" message to the actor to migrate the state.
Versioned Objects
At the cost of one extra byte per object (where our smallest objects are ~100bytes), we can prepend a version field to every object. Then:
- If the version matches, decode the object.
- If the version doesn't match, decode with the previous version's decode logic then apply a transform to to the state.
The downside is:
- A bit of extra on-chain work when reading old state.
- Extra complexity for tools reading on-chain state (they'll need to support historical versions and will need to implement the migration logic).
The upside is that state never actually needs to be migrated. It'll just be transformed on read. Assuming these transforms are light weight (which is the usual case), this should add very little overhead.
Unfortunately, if we change the HAMT/AMT implementations, this solution won't be enough as HAMTs/AMTs are composed of multiple objects. However:
- We can, in most cases, make HAMTs and AMTs more flexible in what they consider to be a valid structure. This would allow us to slowly migrate them piece by piece.
- We don't change these too frequently.