Contract Upgradability#
GenVM provides a native contract upgradability system that allows contracts to be modified after deployment while maintaining security guarantees and clear access controls.
Data that is necessary for this process resides in Root Slot.
Upgrade Control Mechanism#
The upgrade system works through access control during write transactions:
- At start of execution GenVM reads the
upgraderslist of Root Slot. It does not lead to RAM Consumption
- At start of execution GenVM reads the
- If the sender is not in the
upgraderslist of Root Slot, GenVM reads
locked_slotsand will prevent writing to them. It implies \(32*n\) RAM Consumption, where \(n\) is the number of locked slots (bounded by locked_slots). This memory is never released.
- If the sender is not in the
- GenVM loads the contract code as the entry runner. This is a runner
load action; its RAM Consumption is specified in Runners and released when the sub-VM finishes.
Locked Slots in Nested Calls#
The upgraders and locked_slots lists are read once per execution, for
the top-level contract and the top-level sender, before any sub-VM
exists; the resulting charge is the one in Upgrade Control Mechanism and no
sub-VM pays it again.
One set suffices because only the top-level contract’s storage is ever writable within an execution:
A CallContract Message child cannot write storage at all (see Sub-VM Creation), so the callee’s own
locked_slotsare never consulted, and being an upgrader of the callee grants a calling contract nothing.A Sandbox Message child that was granted write_storage writes the same contract’s storage as its parent, under the same sender — the top-level set applies to it unchanged.
A RunNondet Message child cannot write storage.
Contract Major Version#
The major field of Root Slot is at
major and stores the public-ABI major
version that the contract was built against. Top-level and runner loads compare
this byte to CURRENT_MAJOR and fail with
invalid_contract major_mismatch when it
differs. CallContract Message may instead delegate the callee to
another executor selected by the host.
The value is not modifiable by the contract itself: it is written once at deploy time by
the host from a value detected in the contract package (a genvm.version custom WASM
section, a version file inside a zip-packaged runner, or a leading // vX.Y.Z comment
in single-file text contracts). The host detection flow and the on-the-wire endpoint
(POST /contract/detect-version) are described in the impl-spec.
Implications for upgrades:
Replacing
codewith a binary of a different public-ABI major leavesmajorstale; the contract will fail to load on subsequent invocations. Upgraders MUST updatemajorin the same transaction when crossing a major boundary.Bumping
majorto a value the running GenVM does not support produces a load-time error; the upgrade transaction must be performed on a host that already supports the target major.