Skip to content

Commit

Permalink
Merge pull request #452 from near/view-state
Browse files Browse the repository at this point in the history
Implement account.viewState which allows querying contract state directly
  • Loading branch information
vgrichina authored Nov 20, 2020
2 parents 8807885 + 47e6b81 commit 67400fa
Show file tree
Hide file tree
Showing 9 changed files with 99 additions and 13 deletions.
19 changes: 19 additions & 0 deletions lib/account.d.ts

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

23 changes: 23 additions & 0 deletions lib/account.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 1 addition & 3 deletions lib/providers/json-rpc-provider.d.ts

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

15 changes: 10 additions & 5 deletions lib/providers/json-rpc-provider.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions lib/providers/provider.d.ts

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

26 changes: 26 additions & 0 deletions src/account.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import {
SignedTransaction
} from './transaction';
import { FinalExecutionOutcome, TypedError, ErrorContext } from './providers';
import { Finality, BlockId } from './providers/provider';
import { Connection } from './connection';
import {base_decode, base_encode} from './utils/serialize';
import { PublicKey } from './utils/key_pair';
Expand Down Expand Up @@ -379,6 +380,31 @@ export class Account {
return result.result && result.result.length > 0 && parse(Buffer.from(result.result));
}

/**
* See https://docs.near.org/docs/api/rpc#view-contract-state
*
* Returns the state (key value pairs) of this account's contract based on the key prefix.
* Pass an empty string for prefix if you would like to return the entire state.
*
* @param prefix allows to filter which keys should be returned. Empty prefix means all keys. String prefix is utf-8 encoded.
* @param blockQuery specifies which block to query state at. By default returns last "optimistic" block (i.e. not necessarily finalized).
*/
async viewState(prefix: string | Uint8Array, blockQuery: { blockId: BlockId } | { finality: Finality } ): Promise<Array<{ key: Buffer, value: Buffer}>> {
const { blockId, finality } = blockQuery as any || {};
const { values } = await this.connection.provider.query({
request_type: 'view_state',
block_id: blockId,
finality: blockId ? undefined : finality || 'optimistic',
account_id: this.accountId,
prefix_base64: Buffer.from(prefix).toString('base64')
});

return values.map(({key, value}) => ({
key: Buffer.from(key, 'base64'),
value: Buffer.from(value, 'base64')
}))
}

/**
* @returns array of {access_key: AccessKey, public_key: PublicKey} items.
*/
Expand Down
14 changes: 9 additions & 5 deletions src/providers/json-rpc-provider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,13 +68,17 @@ export class JsonRpcProvider extends Provider {

/**
* Query the RPC as [shown in the docs](https://docs.nearprotocol.com/docs/interaction/rpc#query)
* @param path Path parameter for the RPC (ex. "contract/my_token")
* @param data Data parameter (ex. "", "AQ4", or whatever is needed)
*/
async query(path: string, data: string): Promise<any> {
const result = await this.sendJsonRpc('query', [path, data]);
async query(...args: any[]): Promise<any> {
let result;
if (args.length === 1) {
result = await this.sendJsonRpc('query', args[0]);
} else {
const [path, data] = args;
result = await this.sendJsonRpc('query', [path, data]);
}
if (result && result.error) {
throw new Error(`Querying ${path} failed: ${result.error}.\n${JSON.stringify(result, null, 2)}`);
throw new Error(`Querying ${args} failed: ${result.error}.\n${JSON.stringify(result, null, 2)}`);
}
return result;
}
Expand Down
1 change: 1 addition & 0 deletions src/providers/provider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -241,6 +241,7 @@ export abstract class Provider {

abstract async sendTransaction(signedTransaction: SignedTransaction): Promise<FinalExecutionOutcome>;
abstract async txStatus(txHash: Uint8Array, accountId: string): Promise<FinalExecutionOutcome>;
abstract async query(params: object): Promise<any>;
abstract async query(path: string, data: string): Promise<any>;
abstract async block(blockId: BlockId): Promise<BlockResult>;
abstract async chunk(chunkId: ChunkId): Promise<ChunkResult>;
Expand Down
9 changes: 9 additions & 0 deletions test/account.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,15 @@ describe('with deploy contract', () => {
expect(await workingAccount.viewFunction(contractId, 'getValue', {})).toEqual(setCallValue);
});

test('view contract state', async() => {
const setCallValue = testUtils.generateUniqueString('setCallPrefix');
await workingAccount.functionCall(contractId, 'setValue', { value: setCallValue });

const contractAccount = await nearjs.account(contractId);
const state = (await contractAccount.viewState('')).map(({ key, value }) => [key.toString('utf-8'), value.toString('utf-8')]);
expect(state).toEqual([['name', setCallValue]]);
});

test('make function calls via account with custom parser', async() => {
const result = await workingAccount.viewFunction(
contractId,
Expand Down

0 comments on commit 67400fa

Please sign in to comment.