Function ink_env::set_code_hash

source ·
pub fn set_code_hash<E>(code_hash: &E::Hash) -> Result<()>
where E: Environment,
Expand description

Replace the contract code at the specified address with new code.

§Note

There are a few important considerations which must be taken into account when using this API:

  1. The storage at the code hash will remain untouched.

Contract developers must ensure that the storage layout of the new code is compatible with that of the old code.

  1. The contract address (AccountId) remains the same, while the code_hash changes.

Contract addresses are initially derived from hash(deploying_address ++ code_hash ++ salt). This makes it possible to determine a contracts address (AccountId) using the code_hash of the initial code used to instantiate the contract.

However, because set_code_hash can modify the underlying code_hash of a contract, it should not be relied upon that a contracts address can always be derived from its stored code_hash.

  1. Re-entrant calls use new code_hash.

If a contract calls into itself after changing its code the new call would use the new code. However, if the original caller panics after returning from the sub call it would revert the changes made by set_code_hash and the next caller would use the old code.

§Errors

ReturnCode::CodeNotFound in case the supplied code_hash cannot be found on-chain.

§Storage Compatibility

When the smart contract code is modified, it is important to observe an additional virtual restriction that is imposed on this procedure: you should not change the order in which the contract state variables are declared, nor their type.

Violating the restriction will not prevent a successful compilation, but will result in the mix-up of values or failure to read the storage correctly. This can result in severe errors in the application utilizing the contract.

If the storage of your contract looks like this:

#[ink(storage)]
pub struct YourContract {
    x: u32,
    y: bool,
}

The procedures listed below will make it invalid:

Changing the order of variables:

#[ink(storage)]
pub struct YourContract {
    y: bool,
    x: u32,
}

Removing existing variable:

#[ink(storage)]
pub struct YourContract {
    x: u32,
}

Changing type of a variable:

#[ink(storage)]
pub struct YourContract {
    x: u64,
    y: bool,
}

Introducing a new variable before any of the existing ones:

#[ink(storage)]
pub struct YourContract {
    z: Vec<u32>,
    x: u32,
    y: bool,
}

Please refer to the Open Zeppelin docs for more details and examples.