When you change the interface of a contract and re-deploy it, you may see this error:
Why does this happen?
When your contract is executed, the NEAR Runtime reads the serialized state from disk and attempts to load it using current contract code. When your code changes but the serialized state stays the same, it can't figure out how to do this.
How can you avoid such errors?
When you're still in the Research & Development phase, building a prototype and deploying it locally or on testnet, you can just delete all previous contract state when you make a breaking change. See below for a couple ways to do this.
When you're ready to deploy a more stable contract, there are a couple production strategies that will help you update contract state without deleting it all. And once your contract graduates from "trusted mode" (when maintainers control a Full Access key) to community-governed mode (no more Full Access keys), you'll need to know how to upgrade your contract code itself via a DAO vote.
There are two ways to delete all account state:
rm -rf neardev && near dev-deploy
- Deleting & recreating contract account
For both cases, let's consider the following example.
The rust-status-message example contract has the following structure:
Let's say you deploy this contract to testnet, then call it with:
This will return the message that you set with the call to
set_status, in this case
At this point the contract is deployed and has some state.
Now let's say you change the contract to store two kinds of data for each account:
You build & deploy the contract again, thinking that maybe because the new
taglines LookupMap has the same prefix as the old
records LookupMap (the prefix is
r, set by
LookupMap::new(b"r".to_vec())), the tagline for
you.testnet should be
"lol". But when you
near view the contract, you get the "Cannot deserialize" message. What to do?
rm -rf neardev && near dev-deploy#
When first getting started with a new project, the fastest way to deploy a contract is
This does a few things:
- Creates a new testnet account with a name like
- Stores this account name in a
neardevfolder within the project
- Stores the private key for this account in the
- Deploys your contract code to this account
The next time you run
dev-deploy, it checks the
neardev folder and re-deploys to the same account rather than making a new one.
But in the example above, we want to delete the account state. How do we do that?
The easiest way is just to delete the
neardev folder, then run
near dev-deploy again. This will create a brand new testnet account, with its own (empty) state, and deploy the updated contract to it.
If you want to have a predictable account name rather than an ever-changing
dev-* account, the best way is probably to create a sub-account:
Then deploy your contract to it:
In this case, how do you delete all contract state and start again? Delete the sub-account and recreate it.
This sends all funds still on the
app-name.you.testnet account to
you.testnet and deletes the contract that had been deployed to it, including all contract state.
Now you create the sub-account and deploy to it again using the commands above, and it will have empty state like it did the first time you deployed it.