fix: query Nonce account
This commit is contained in:
parent
c9cc44ae4f
commit
600a295b11
|
@ -7,8 +7,9 @@ import jayson from 'jayson/lib/client/browser';
|
|||
import {struct} from 'superstruct';
|
||||
import {Client as RpcWebSocketClient} from 'rpc-websockets';
|
||||
|
||||
import {DEFAULT_TICKS_PER_SLOT, NUM_TICKS_PER_SECOND} from './timing';
|
||||
import {NonceAccount} from './nonce-account';
|
||||
import {PublicKey} from './publickey';
|
||||
import {DEFAULT_TICKS_PER_SLOT, NUM_TICKS_PER_SECOND} from './timing';
|
||||
import {Transaction} from './transaction';
|
||||
import {sleep} from './util/sleep';
|
||||
import type {Blockhash} from './blockhash';
|
||||
|
@ -1149,6 +1150,55 @@ export class Connection {
|
|||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch the contents of a Nonce account from the cluster
|
||||
*/
|
||||
async getNonceAndContext(
|
||||
nonceAccount: PublicKey,
|
||||
commitment: ?Commitment,
|
||||
): Promise<RpcResponseAndContext<NonceAccount>> {
|
||||
const args = this._argsWithCommitment(
|
||||
[nonceAccount.toBase58()],
|
||||
commitment,
|
||||
);
|
||||
const unsafeRes = await this._rpcRequest('getAccountInfo', args);
|
||||
const res = GetAccountInfoAndContextRpcResult(unsafeRes);
|
||||
if (res.error) {
|
||||
throw new Error(res.error.message);
|
||||
}
|
||||
assert(typeof res.result !== 'undefined');
|
||||
|
||||
const isV021 =
|
||||
typeof res.result.context !== 'undefined' &&
|
||||
typeof res.result.value !== 'undefined';
|
||||
|
||||
const slot = isV021 ? res.result.context.slot : NaN;
|
||||
const resultValue = isV021 ? res.result.value : res.result;
|
||||
|
||||
if (!resultValue) {
|
||||
throw new Error('Invalid request');
|
||||
}
|
||||
|
||||
const value = NonceAccount.fromAccountData(Buffer.from(resultValue.data));
|
||||
|
||||
return {
|
||||
context: {
|
||||
slot,
|
||||
},
|
||||
value,
|
||||
};
|
||||
}
|
||||
async getNonce(
|
||||
nonceAccount: PublicKey,
|
||||
commitment: ?Commitment,
|
||||
): Promise<NonceAccount> {
|
||||
return await this.getNonceAndContext(nonceAccount, commitment)
|
||||
.then(x => x.value)
|
||||
.catch(e => {
|
||||
throw e;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Request an allocation of lamports to the specified account
|
||||
*/
|
||||
|
|
|
@ -4,6 +4,7 @@ export {BpfLoader} from './bpf-loader';
|
|||
export {BudgetProgram} from './budget-program';
|
||||
export {Connection} from './connection';
|
||||
export {Loader} from './loader';
|
||||
export {NonceAccount} from './nonce-account';
|
||||
export {PublicKey} from './publickey';
|
||||
export {
|
||||
STAKE_CONFIG_ID,
|
||||
|
|
|
@ -0,0 +1,40 @@
|
|||
// @flow
|
||||
import * as BufferLayout from 'buffer-layout';
|
||||
|
||||
import type {Blockhash} from './blockhash';
|
||||
import * as Layout from './layout';
|
||||
import {PublicKey} from './publickey';
|
||||
|
||||
/**
|
||||
* See https://github.com/solana-labs/solana/blob/0ea2843ec9cdc517572b8e62c959f41b55cf4453/sdk/src/nonce_state.rs#L29-L32
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
const NonceAccountLayout = BufferLayout.struct([
|
||||
BufferLayout.u32('state'),
|
||||
Layout.publicKey('authorizedPubkey'),
|
||||
Layout.publicKey('hash'),
|
||||
]);
|
||||
|
||||
/**
|
||||
* NonceAccount class
|
||||
*/
|
||||
export class NonceAccount {
|
||||
authorizedPubkey: PublicKey;
|
||||
nonce: Blockhash;
|
||||
|
||||
/**
|
||||
* Deserialize NonceAccount from the account data.
|
||||
*
|
||||
* @param buffer account data
|
||||
* @return NonceAccount
|
||||
*/
|
||||
static fromAccountData(buffer: Buffer): NonceAccount {
|
||||
const nonceAccount = NonceAccountLayout.decode(buffer, 0);
|
||||
nonceAccount.authorizedPubkey = new PublicKey(
|
||||
nonceAccount.authorizedPubkey,
|
||||
);
|
||||
nonceAccount.nonce = new PublicKey(nonceAccount.nonce).toString();
|
||||
return nonceAccount;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,154 @@
|
|||
// @flow
|
||||
|
||||
import bs58 from 'bs58';
|
||||
|
||||
import {Account, Connection, SystemProgram} from '../src';
|
||||
import {mockRpc, mockRpcEnabled} from './__mocks__/node-fetch';
|
||||
import {mockGetRecentBlockhash} from './mockrpc/get-recent-blockhash';
|
||||
import {url} from './url';
|
||||
|
||||
if (!mockRpcEnabled) {
|
||||
// Testing max commitment level takes around 20s to complete
|
||||
jest.setTimeout(30000);
|
||||
}
|
||||
|
||||
test('create and query nonce account', async () => {
|
||||
const from = new Account();
|
||||
const nonceAccount = new Account();
|
||||
const connection = new Connection(url, 'recent');
|
||||
|
||||
mockRpc.push([
|
||||
url,
|
||||
{
|
||||
method: 'getMinimumBalanceForRentExemption',
|
||||
params: [68, {commitment: 'recent'}],
|
||||
},
|
||||
{
|
||||
error: null,
|
||||
result: 50,
|
||||
},
|
||||
]);
|
||||
|
||||
const minimumAmount = await connection.getMinimumBalanceForRentExemption(
|
||||
SystemProgram.nonceSpace,
|
||||
'recent',
|
||||
);
|
||||
|
||||
mockRpc.push([
|
||||
url,
|
||||
{
|
||||
method: 'requestAirdrop',
|
||||
params: [
|
||||
from.publicKey.toBase58(),
|
||||
minimumAmount * 2,
|
||||
{commitment: 'recent'},
|
||||
],
|
||||
},
|
||||
{
|
||||
error: null,
|
||||
result:
|
||||
'1WE5w4B7v59x6qjyC4FbG2FEKYKQfvsJwqSxNVmtMjT8TQ31hsZieDHcSgqzxiAoTL56n2w5TncjqEKjLhtF4Vk',
|
||||
},
|
||||
]);
|
||||
|
||||
await connection.requestAirdrop(from.publicKey, minimumAmount * 2);
|
||||
|
||||
mockRpc.push([
|
||||
url,
|
||||
{
|
||||
method: 'getBalance',
|
||||
params: [from.publicKey.toBase58(), {commitment: 'recent'}],
|
||||
},
|
||||
{
|
||||
error: null,
|
||||
result: minimumAmount * 2,
|
||||
},
|
||||
]);
|
||||
|
||||
const balance = await connection.getBalance(from.publicKey);
|
||||
expect(balance).toBe(minimumAmount * 2);
|
||||
|
||||
mockGetRecentBlockhash('recent');
|
||||
mockRpc.push([
|
||||
url,
|
||||
{
|
||||
method: 'sendTransaction',
|
||||
},
|
||||
{
|
||||
error: null,
|
||||
result:
|
||||
'3WE5w4B7v59x6qjyC4FbG2FEKYKQfvsJwqSxNVmtMjT8TQ31hsZieDHcSgqzxiAoTL56n2w5TncjqEKjLhtF4Vk',
|
||||
},
|
||||
]);
|
||||
|
||||
const transaction = SystemProgram.createNonceAccount(
|
||||
from.publicKey,
|
||||
nonceAccount.publicKey,
|
||||
from.publicKey,
|
||||
minimumAmount,
|
||||
);
|
||||
await connection.sendTransaction(transaction, from, nonceAccount);
|
||||
|
||||
const expectedData = Buffer.alloc(68);
|
||||
expectedData.writeInt32LE(1, 0);
|
||||
from.publicKey.toBuffer().copy(expectedData, 4);
|
||||
const mockNonce = new Account();
|
||||
mockNonce.publicKey.toBuffer().copy(expectedData, 36);
|
||||
|
||||
mockRpc.push([
|
||||
url,
|
||||
{
|
||||
method: 'getAccountInfo',
|
||||
params: [nonceAccount.publicKey.toBase58(), {commitment: 'recent'}],
|
||||
},
|
||||
{
|
||||
error: null,
|
||||
result: {
|
||||
owner: [
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
],
|
||||
lamports: minimumAmount,
|
||||
data: [...expectedData],
|
||||
executable: false,
|
||||
},
|
||||
},
|
||||
]);
|
||||
//
|
||||
const nonceAccountData = await connection.getNonce(
|
||||
nonceAccount.publicKey,
|
||||
'recent',
|
||||
);
|
||||
expect(nonceAccountData.authorizedPubkey).toEqual(from.publicKey);
|
||||
expect(bs58.decode(nonceAccountData.nonce).length).toBeGreaterThan(30);
|
||||
});
|
Loading…
Reference in New Issue