Closed crodriguezvega closed 1 year ago
Thinking about flows where we can use wasm's feature of contract migration.
In x/wasm
contract migration requires the contract to have an address, which is passed in the env
parameter. In 08-wasm we currently do not have addresses for the light client contracts. In x/wasm
the contract address is generated during contract instantiation, each contract instance gets its own contract address.
In x/wasm
there is MsgMigrateContract
with a field contract
that is the address of the contract that should be migrated. The code_id
field references the new contract that migrates to. MsgInstantiateContract
has an admin
field that specify who can perform migrations and this is stored in the ContractInfo
during contract instantiation.
During migration it is checked that the caller (the signer of MsgMigrateContract
can modify the contract (it uses the admin address stored in ContractInto
during instantiation. In case of governance, the admin address does not matter, since the governance policy will allow migration if the signer is the governance module.
To execute the migration, the env
variable passed to wasmVM.Migrate
contains the address of the contract that should be migrated. In the call to wasmVM.Migrate
the code hash of the new contract is also passed.
If we want to use the migrate feature of wasmVM
we need to have an address for each contract that is instantiated. In the Initialize
function we instantiate the contract, so we can generate a contract address using the code hash and a similar trick as we do when we generate the interchain account address. In the Initialize
function we also have access to the client store, so we could store the contract address under a contracAddress
key. The contract address that we generate in Initialize
should then be passed to wasmVM.Instantiate
in the env
parameter.
x/wasm
exposes contract addresses to the external world and implements an elaborate permission scheme for migration, but in 08-wasm we could keep it simple and do not use contract addresses outside of the module (i.e. addresses would only be known and used inside the module).
migrateClient
In migrateClient
:
Status
on the substitute client.wasmVM.Migrate
with the contract address and the new code hash. If the code hashes are the same, we can skip this step.MigrateClient
on the contract to replace the client state of the subject with the client state of the substitute.In order to use the client recovery flow for contract migration we would need to either change the check in 02-client's RecoverClient
that enforces the subject client to not be active or execute in the same governance proposal that would execute RecoverClient
another message that would make the subject client not active first, so that we can progress beyond the check in 02-client. Maybe there other alternatives as well.
We could have a new message (e.g. MsgMigrateContract
) and RPC endpoint (e.g. MigrateContract
). MsgMigrateContract
could have the following fields:
msg
field with the bytes that can be passed to the contract at migration, even if we don't use them right now.We don't need to have a field for the code hash of the contract we migrate from, since we have the client ID and with it we can access the client store and retrieve the contract address.that we need to use in the call to wasmVM.Migrate
.
In MigrateContract
:
wasmVM.Migrate
with the contract address and the new code hash.The main advantage of this approach is that we do not require modifications to 02-client to change the check that enforces subject clients to not be active if they are going to be recovered, or an extra message in the governance proposal to make the client not active.
The disadvantage is that we still need to deal with the situation where a client is recoverd and the new client state has a new code hash. We could either enforce in migrateClient
that the code hash cannot change during client recovery, or alternatively implement the proposal for migrateClient
above (i.e. we migrate the contract and update client state).
I'm in favour of using wasmVM.Migrate
. Isn't it possible for us to use the clientID (ex 08-wasm-0
) as the contract address? We could also make this a more general thing (for example providing the clientID as contract address to the Env)
We discussed and decided to implement the new RPC endpoint for migrating the byte code of a contract (for which I will open a new issue). We will close this issue and use https://github.com/cosmos/ibc-go/issues/4862 for the implementation changes needed in CheckSubstituteAndUpdateState
.
Based on feedback received on Ethan Frey's audit of 08-wasm, the
CheckSubsituteAndUpdateState
function of theClientState
interface is overloaded (updates the client state, the consensus state and its associated metadata) and error prone. We acknowledge this and see the benefit of splitting this API into 2 different functions.This issue addresses the implementation of the first function, one that would update only the client state. For the time being, the 02-client
ClientState
interface function is not modified and this new function may be implemented only in 08-wasm's ownClientState
implementation and be used in its implementation ofCheckSubsituteAndUpdateState
.Possible pseudo-code for the function:
Contracts will need to implement the function to handle the
migrateClientMsg
message.We also agreed that we could use the client recovery flow to migrate to a new contract, if needed (e.g. in the situation that a new contract needs to be deployed to fix a bug). However, as I am writing this I just realised that for this to work we need the light client with the existing contract to expire first (or make it not active somehow), since we check in 02-client's
RecoverClient
that the subject client is not active. For this reason I am adding theneeds discussion
label to discuss how to handle this.