near / near-sdk-rs

Rust library for writing NEAR smart contracts
https://near-sdk.io
Apache License 2.0
454 stars 243 forks source link

env::state_write has no effect #365

Closed ailisp closed 3 years ago

ailisp commented 3 years ago

To do a minimum repro, deploy any contract, for example, I deployed status-message.wasm on a local node. Add a new method:

pub fn migrate(&mut self) {
    let s = "a".to_string();
    env::state_write(&s); // this destroy the state, any later operation on this contract should fail because it will fail to borsh deserialize
// or similar, do: env::storage(b"STATE", b"what");
}

deploy the new contract, call migrate and this txn success. Then call a view method get_status, it still success. Further more, if you do:

curl http://localhost:3030 -H 'Content-Type: application/json' -d '{"jsonrpc":"2.0", "id":1, "method":"query", "params":{"request_type":"view_state","block_id":3390,"account_id":"test.near","prefix_base64":""}}'

to inspect state before and after the call (by replacing block_id), it shows the same state. So this indicates state_write/storage_write has no effect.

Full step to repro:

export NEAR_ENV=local
near deploy test.near status_message.wasm 
near call test.near set_status '{"message":"hello"}' --accountId test.near
near call test.near migrate '' --accountId test.near
near view test.near get_status '{"account_id":"test.near"}' --accountId test.near
curl http://localhost:3030 -H 'Content-Type: application/json' -d '{"jsonrpc":"2.0", "id":1, "method":"query", "params":{"request_type":"view_state","block_id":3390,"account_id":"test.near","prefix_base64":""}}'
ailisp commented 3 years ago

@frol I took your answer from stackoverflow to try testing migrate state in a local node, then it seems that txn success but have no effect, then I further realize it's indeed env::write_state/storage_write has no effect

abacabadabacaba commented 3 years ago

If a method has &mut self parameter, then SDK will generate code to read the state before the call and write the state after the call. The latter operation will overwrite whatever you wrote manually. You should probably not add self parameter to a migration method.

ailisp commented 3 years ago

@abacabadabacaba is correct. Indeed, I do need the self parameter as I need to read some state, mutate them in the migration method. I can use env::read but has a &self has sdk deserialize it for you is easier. And just make the migration method from &mut self to &self and near call it works.

matklad commented 3 years ago

Feels like there's still at least a documentation problem here tbh.