#`update` tries to get the admin from the wrong storage type

15 messages · Page 1 of 1 (latest)

dusk abyss
#
pub fn update(env: Env, new_wasm_hash: BytesN<32>) {
    let admin: Address = env.storage().instance().get(&DataKey::Admin).unwrap();
    admin.require_auth();
    env.deployer().update_current_contract_wasm(new_wasm_hash);
}

Is it possible to update the contract, if the admin is actually under the persistent storage?
Right now the function fails, since it can't find the value under the instance storage (which is interesting, because it used to be an instance - the value should be there from before).

Is it possible to somehow inject a function into a contract? For example in another blockchain during migration the function is being read from the target contract, not from the source.

steel basin
#

Is it possible to somehow inject a function into a contract?
no, not at the moment. in the future we could add a hook similar to constructor, that would be executed after the update has succeeded. for now you could achieve the same result by calling update on the old contract, then some process_update function on the new one (i.e. that would be 2 calls to your contract).
that said, I'm not sure I understand your issue

#

Right now the function fails, since it can't find the value under the instance storage
did you put the value in the instance storage?

dusk abyss
#

I can't call update on the old contract because it fails on the get admin call.

Admin used to be kept in the instance storage, was changed to the persistent one. Admin has not changed in the mean time.

steel basin
#

how could it be changed?

#

unfortunately, this seems like a bug in the contract to me. I don't think we can do anything

#

it's a good idea to test all the functionality of the contract before deploying it, as it's not possible to modify its logic beyond the source updates

dusk abyss
#

Yes, we have created a custom test harness to test the migration.

Actually I'm quite surprised, the admin was kept in the instance storage, later it was changed to the persistent one (the new .set() was called). I would assume that the value should be readable from both places still.

steel basin
#

just to make sure I understand this correctly, did you change the code itself before deploying the contract? i.e. admin is written to persistent storage, but read from the instance storage

#

I would assume that the value should be readable from both places still.
every storage type has its own key space (otherwise doing something like storage().instance().set(key, 20); storage().persistent().set(key, 30); would be ambiguous). but I see that our documentation doesn't make this clear enough, sorry about that 😦

#

do you not have any ways in your contract to put admin into instance storage as well?

#

basically if there is no way to write admin into your instance storage, then unfortunately it seems like the best way to proceed is to deploy another instance of the contract that would use new (and fixed) wasm.

turbid wharf
#

You could try checking the value of the instance ledger entry. As I understand it, instance storage is just a ContractDataLedgerEntry under the key ledger_key_contract_instance. So you could look it up via the rpc. Not enirely sure though

turbid wharf
steel basin
#

of course you can look this up off-chain. the issue is that if contract's logic is 'hard-wired' to a wrong key, there is really no way around that. that's a keystone of security of the smart contracts, but it unfortunately makes issues like this very hard to address