Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add clean state example #61

Merged
merged 5 commits into from
May 26, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion .github/workflows/examples.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,4 +24,6 @@ jobs:
- name: status-message
run: cd examples/status-message && yarn && yarn build && yarn test && cd ../..
- name: status-message-collections
run: cd examples/status-message-collections && yarn && yarn build && yarn test && cd ../..
run: cd examples/status-message-collections && yarn && yarn build && yarn test && cd ../..
- name: clean-state
run: cd examples/clean-state && yarn && yarn build && yarn test && cd ../..
2 changes: 2 additions & 0 deletions examples/clean-state/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
build
node_modules
38 changes: 38 additions & 0 deletions examples/clean-state/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
# Clean state contract in JavaScript

This is an equivalent JavaScript implementation of the clean state example.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I suggest to add a short instruction about how to use this contract. In summary, the steps are:

  1. Deploy this contract to the account where you want to clean up state
  2. Call the contract with known state keys to clean state. If delete all keys doesn't fit gas limit, you may need to do it a few times
  3. Once finished clean up state, Deploy the original contract or delete the contract code with near js remove

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done, PTAL

## Build the contract

First ensure JSVM contract is build and deployed locally, follow [Local Installation](https://github.com/near/near-sdk-js#local-installation). Then run:
```
npm i
npm run build
```

## Test the contract with workspaces-js
```
npm run test
```

## Guide on how to clean arbitrary account's state

First, build the contract as described above and deploy it to the account which state you want to clean up (this will override the contract that is currently there, but you can then re-deploy the original contract after the cleanup is done). Assuming that you are using JSVM contract deployed to `jsvm.testnet`, run the following command:

```
near call jsvm.testnet deploy_js_contract --accountId account-to-cleanup.testnet --args $(cat build/contract.base64) --base64 --deposit 0.1
```

Now, you can call the `clean` method to delete the unwanted keys:

```
near call jsvm.testnet call_js_contract --accountId account-to-cleanup.testnet --base64 --args $(node encode_call.js account-to-cleanup.testnet clean '[["key1", "key2"]]') --deposit 0.1
```

If gas limit prevents you from deleting all keys you want at once, just split the array into multiple parts and make a few subsequent `clean` calls.

Once you are done, just de-deploy the original contract and you should be all set:

```
near call jsvm.testnet deploy_js_contract --accountId account-to-cleanup.testnet --args $(cat path-to-original-contract.base64) --base64 --deposit 0.1
```
52 changes: 52 additions & 0 deletions examples/clean-state/__tests__/test-clean-state.ava.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import { Worker } from 'near-workspaces';
import { readFile } from 'fs/promises'
import test from 'ava';

// TODO: make this function part of the npm package when it is available
function encodeCall(contract, method, args) {
return Buffer.concat([Buffer.from(contract), Buffer.from([0]), Buffer.from(method), Buffer.from([0]), Buffer.from(JSON.stringify(args))])
}

test.beforeEach(async t => {
// Init the worker and start a Sandbox server
const worker = await Worker.init();

// Prepare sandbox for tests, create accounts, deploy contracts, etx.
const root = worker.rootAccount;

// Deploy the jsvm contract.
const jsvm = await root.createAndDeploy(
root.getSubAccount('jsvm').accountId,
'./node_modules/near-sdk-js/res/jsvm.wasm',
);

// Deploy clean state contract
const cleanStateContract = await root.createSubAccount('clean-state');
let cleanStateContractBase64 = (await readFile('build/contract.base64')).toString();
await cleanStateContract.call(jsvm, 'deploy_js_contract', Buffer.from(cleanStateContractBase64, 'base64'), { attachedDeposit: '400000000000000000000000' });
await cleanStateContract.call(jsvm, 'call_js_contract', encodeCall(cleanStateContract.accountId, 'init', []), { attachedDeposit: '400000000000000000000000' });

// Save state for test runs, it is unique for each test
t.context.worker = worker;
t.context.accounts = {
root,
jsvm,
cleanStateContract,
};
});

test.afterEach(async t => {
await t.context.worker.tearDown().catch(error => {
console.log('Failed tear down the worker:', error);
});
});

test('Clean state after storing', async t => {
const { jsvm, cleanStateContract } = t.context.accounts;
await cleanStateContract.call(jsvm, 'call_js_contract', encodeCall(cleanStateContract.accountId, 'put', ['1', 1]), { attachedDeposit: '400000000000000000000000' });
const value1 = await jsvm.view('view_js_contract', encodeCall(cleanStateContract.accountId, 'get', ['1']));
t.is(value1, '1');
await cleanStateContract.call(jsvm, 'call_js_contract', encodeCall(cleanStateContract.accountId, 'clean', [['1']]), { attachedDeposit: '400000000000000000000000' });
const value2 = await jsvm.view('view_js_contract', encodeCall(cleanStateContract.accountId, 'get', ['1']));
t.is(value2, null);
});
8 changes: 8 additions & 0 deletions examples/clean-state/ava.config.cjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
require('util').inspect.defaultOptions.depth = 5; // Increase AVA's printing depth

module.exports = {
timeout: '300000',
files: ['**/*.ava.js'],
failWithoutAssertions: false,
extensions: ['js'],
};
6 changes: 6 additions & 0 deletions examples/clean-state/babel.config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"plugins": [
"near-sdk-js/src/build-tools/near-bindgen-exporter",
["@babel/plugin-proposal-decorators", {"version": "legacy"}]
]
}
Loading