2020-01-02 17:54:43 -08:00
|
|
|
// @flow
|
|
|
|
|
|
|
|
import bs58 from 'bs58';
|
|
|
|
|
2020-09-10 00:43:32 -07:00
|
|
|
import {
|
|
|
|
Account,
|
|
|
|
Connection,
|
|
|
|
SystemProgram,
|
|
|
|
Transaction,
|
|
|
|
PublicKey,
|
|
|
|
} from '../src';
|
2020-03-05 08:44:56 -08:00
|
|
|
import {NONCE_ACCOUNT_LENGTH} from '../src/nonce-account';
|
2020-01-02 17:54:43 -08:00
|
|
|
import {mockRpc, mockRpcEnabled} from './__mocks__/node-fetch';
|
|
|
|
import {mockGetRecentBlockhash} from './mockrpc/get-recent-blockhash';
|
|
|
|
import {url} from './url';
|
2020-07-08 05:46:16 -07:00
|
|
|
import {mockConfirmTransaction} from './mockrpc/confirm-transaction';
|
2020-01-02 17:54:43 -08:00
|
|
|
|
|
|
|
if (!mockRpcEnabled) {
|
|
|
|
// Testing max commitment level takes around 20s to complete
|
|
|
|
jest.setTimeout(30000);
|
|
|
|
}
|
|
|
|
|
2020-08-15 21:38:11 -07:00
|
|
|
const expectedData = (authorizedPubkey: PublicKey): [string, string] => {
|
2020-05-04 22:30:55 -07:00
|
|
|
const expectedData = Buffer.alloc(NONCE_ACCOUNT_LENGTH);
|
|
|
|
expectedData.writeInt32LE(0, 0); // Version, 4 bytes
|
|
|
|
expectedData.writeInt32LE(1, 4); // State, 4 bytes
|
|
|
|
authorizedPubkey.toBuffer().copy(expectedData, 8); // authorizedPubkey, 32 bytes
|
|
|
|
const mockNonce = new Account();
|
|
|
|
mockNonce.publicKey.toBuffer().copy(expectedData, 40); // Hash, 32 bytes
|
|
|
|
expectedData.writeUInt16LE(5000, 72); // feeCalculator, 8 bytes
|
2020-08-15 21:57:23 -07:00
|
|
|
return [expectedData.toString('base64'), 'base64'];
|
2020-05-04 22:30:55 -07:00
|
|
|
};
|
|
|
|
|
2020-01-02 17:54:43 -08:00
|
|
|
test('create and query nonce account', async () => {
|
|
|
|
const from = new Account();
|
|
|
|
const nonceAccount = new Account();
|
2020-12-24 10:43:45 -08:00
|
|
|
const connection = new Connection(url, 'singleGossip');
|
2020-01-02 17:54:43 -08:00
|
|
|
|
|
|
|
mockRpc.push([
|
|
|
|
url,
|
|
|
|
{
|
|
|
|
method: 'getMinimumBalanceForRentExemption',
|
2020-12-24 10:43:45 -08:00
|
|
|
params: [NONCE_ACCOUNT_LENGTH, {commitment: 'singleGossip'}],
|
2020-01-02 17:54:43 -08:00
|
|
|
},
|
|
|
|
{
|
|
|
|
error: null,
|
|
|
|
result: 50,
|
|
|
|
},
|
|
|
|
]);
|
|
|
|
|
|
|
|
const minimumAmount = await connection.getMinimumBalanceForRentExemption(
|
2020-03-05 08:44:56 -08:00
|
|
|
NONCE_ACCOUNT_LENGTH,
|
2020-01-02 17:54:43 -08:00
|
|
|
);
|
|
|
|
|
|
|
|
mockRpc.push([
|
|
|
|
url,
|
|
|
|
{
|
|
|
|
method: 'requestAirdrop',
|
2020-06-10 09:10:25 -07:00
|
|
|
params: [from.publicKey.toBase58(), minimumAmount * 2],
|
2020-01-02 17:54:43 -08:00
|
|
|
},
|
|
|
|
{
|
|
|
|
error: null,
|
|
|
|
result:
|
|
|
|
'1WE5w4B7v59x6qjyC4FbG2FEKYKQfvsJwqSxNVmtMjT8TQ31hsZieDHcSgqzxiAoTL56n2w5TncjqEKjLhtF4Vk',
|
|
|
|
},
|
|
|
|
]);
|
|
|
|
|
2020-07-08 05:46:16 -07:00
|
|
|
const signature = await connection.requestAirdrop(
|
|
|
|
from.publicKey,
|
|
|
|
minimumAmount * 2,
|
|
|
|
);
|
|
|
|
mockConfirmTransaction(signature);
|
2020-12-24 10:43:45 -08:00
|
|
|
await connection.confirmTransaction(signature, 'singleGossip');
|
2020-01-02 17:54:43 -08:00
|
|
|
|
|
|
|
mockRpc.push([
|
|
|
|
url,
|
|
|
|
{
|
|
|
|
method: 'getBalance',
|
2020-12-24 10:43:45 -08:00
|
|
|
params: [from.publicKey.toBase58(), {commitment: 'singleGossip'}],
|
2020-01-02 17:54:43 -08:00
|
|
|
},
|
|
|
|
{
|
|
|
|
error: null,
|
2020-01-08 12:59:58 -08:00
|
|
|
result: {
|
|
|
|
context: {
|
|
|
|
slot: 11,
|
|
|
|
},
|
|
|
|
value: minimumAmount * 2,
|
|
|
|
},
|
2020-01-02 17:54:43 -08:00
|
|
|
},
|
|
|
|
]);
|
|
|
|
|
|
|
|
const balance = await connection.getBalance(from.publicKey);
|
|
|
|
expect(balance).toBe(minimumAmount * 2);
|
|
|
|
|
2020-06-03 04:55:42 -07:00
|
|
|
mockGetRecentBlockhash('max');
|
2020-01-02 17:54:43 -08:00
|
|
|
mockRpc.push([
|
|
|
|
url,
|
|
|
|
{
|
|
|
|
method: 'sendTransaction',
|
|
|
|
},
|
|
|
|
{
|
|
|
|
error: null,
|
|
|
|
result:
|
|
|
|
'3WE5w4B7v59x6qjyC4FbG2FEKYKQfvsJwqSxNVmtMjT8TQ31hsZieDHcSgqzxiAoTL56n2w5TncjqEKjLhtF4Vk',
|
|
|
|
},
|
|
|
|
]);
|
|
|
|
|
2020-09-10 00:43:32 -07:00
|
|
|
const transaction = new Transaction().add(
|
|
|
|
SystemProgram.createNonceAccount({
|
|
|
|
fromPubkey: from.publicKey,
|
|
|
|
noncePubkey: nonceAccount.publicKey,
|
|
|
|
authorizedPubkey: from.publicKey,
|
|
|
|
lamports: minimumAmount,
|
|
|
|
}),
|
|
|
|
);
|
2020-07-08 05:46:16 -07:00
|
|
|
const nonceSignature = await connection.sendTransaction(
|
|
|
|
transaction,
|
|
|
|
[from, nonceAccount],
|
|
|
|
{
|
|
|
|
skipPreflight: true,
|
|
|
|
},
|
|
|
|
);
|
|
|
|
mockConfirmTransaction(nonceSignature);
|
2020-12-24 10:43:45 -08:00
|
|
|
await connection.confirmTransaction(nonceSignature, 'singleGossip');
|
2020-01-02 17:54:43 -08:00
|
|
|
|
|
|
|
mockRpc.push([
|
|
|
|
url,
|
|
|
|
{
|
|
|
|
method: 'getAccountInfo',
|
2020-08-15 21:38:11 -07:00
|
|
|
params: [
|
|
|
|
nonceAccount.publicKey.toBase58(),
|
2020-12-24 10:43:45 -08:00
|
|
|
{encoding: 'base64', commitment: 'singleGossip'},
|
2020-08-15 21:38:11 -07:00
|
|
|
],
|
2020-01-02 17:54:43 -08:00
|
|
|
},
|
|
|
|
{
|
|
|
|
error: null,
|
|
|
|
result: {
|
2020-01-08 12:59:58 -08:00
|
|
|
context: {
|
|
|
|
slot: 11,
|
|
|
|
},
|
|
|
|
value: {
|
2020-01-15 13:04:26 -08:00
|
|
|
owner: '11111111111111111111111111111111',
|
2020-01-08 12:59:58 -08:00
|
|
|
lamports: minimumAmount,
|
2020-05-04 22:30:55 -07:00
|
|
|
data: expectedData(from.publicKey),
|
2020-01-08 12:59:58 -08:00
|
|
|
executable: false,
|
|
|
|
},
|
2020-01-02 17:54:43 -08:00
|
|
|
},
|
|
|
|
},
|
|
|
|
]);
|
|
|
|
//
|
2020-05-04 22:30:55 -07:00
|
|
|
const nonceAccountData = await connection.getNonce(nonceAccount.publicKey);
|
|
|
|
if (nonceAccountData === null) {
|
|
|
|
expect(nonceAccountData).not.toBeNull();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
expect(nonceAccountData.authorizedPubkey).toEqual(from.publicKey);
|
|
|
|
expect(bs58.decode(nonceAccountData.nonce).length).toBeGreaterThan(30);
|
|
|
|
});
|
|
|
|
|
|
|
|
test('create and query nonce account with seed', async () => {
|
|
|
|
const from = new Account();
|
|
|
|
const seed = 'seed';
|
|
|
|
const noncePubkey = await PublicKey.createWithSeed(
|
|
|
|
from.publicKey,
|
|
|
|
seed,
|
|
|
|
SystemProgram.programId,
|
|
|
|
);
|
2020-12-24 10:43:45 -08:00
|
|
|
const connection = new Connection(url, 'singleGossip');
|
2020-05-04 22:30:55 -07:00
|
|
|
|
|
|
|
mockRpc.push([
|
|
|
|
url,
|
|
|
|
{
|
|
|
|
method: 'getMinimumBalanceForRentExemption',
|
2020-12-24 10:43:45 -08:00
|
|
|
params: [NONCE_ACCOUNT_LENGTH, {commitment: 'singleGossip'}],
|
2020-05-04 22:30:55 -07:00
|
|
|
},
|
|
|
|
{
|
|
|
|
error: null,
|
|
|
|
result: 50,
|
|
|
|
},
|
|
|
|
]);
|
|
|
|
|
|
|
|
const minimumAmount = await connection.getMinimumBalanceForRentExemption(
|
|
|
|
NONCE_ACCOUNT_LENGTH,
|
2020-01-02 17:54:43 -08:00
|
|
|
);
|
2020-05-04 22:30:55 -07:00
|
|
|
|
|
|
|
mockRpc.push([
|
|
|
|
url,
|
|
|
|
{
|
|
|
|
method: 'requestAirdrop',
|
2020-06-10 09:10:25 -07:00
|
|
|
params: [from.publicKey.toBase58(), minimumAmount * 2],
|
2020-05-04 22:30:55 -07:00
|
|
|
},
|
|
|
|
{
|
|
|
|
error: null,
|
|
|
|
result:
|
|
|
|
'1WE5w4B7v59x6qjyC4FbG2FEKYKQfvsJwqSxNVmtMjT8TQ31hsZieDHcSgqzxiAoTL56n2w5TncjqEKjLhtF4Vk',
|
|
|
|
},
|
|
|
|
]);
|
|
|
|
|
2020-07-08 05:46:16 -07:00
|
|
|
const signature = await connection.requestAirdrop(
|
|
|
|
from.publicKey,
|
|
|
|
minimumAmount * 2,
|
|
|
|
);
|
|
|
|
mockConfirmTransaction(signature);
|
2020-12-24 10:43:45 -08:00
|
|
|
await connection.confirmTransaction(signature, 'singleGossip');
|
2020-05-04 22:30:55 -07:00
|
|
|
|
|
|
|
mockRpc.push([
|
|
|
|
url,
|
|
|
|
{
|
|
|
|
method: 'getBalance',
|
2020-12-24 10:43:45 -08:00
|
|
|
params: [from.publicKey.toBase58(), {commitment: 'singleGossip'}],
|
2020-05-04 22:30:55 -07:00
|
|
|
},
|
|
|
|
{
|
|
|
|
error: null,
|
|
|
|
result: {
|
|
|
|
context: {
|
|
|
|
slot: 11,
|
|
|
|
},
|
|
|
|
value: minimumAmount * 2,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
]);
|
|
|
|
|
|
|
|
const balance = await connection.getBalance(from.publicKey);
|
|
|
|
expect(balance).toBe(minimumAmount * 2);
|
|
|
|
|
2020-06-03 04:55:42 -07:00
|
|
|
mockGetRecentBlockhash('max');
|
2020-05-04 22:30:55 -07:00
|
|
|
mockRpc.push([
|
|
|
|
url,
|
|
|
|
{
|
|
|
|
method: 'sendTransaction',
|
|
|
|
},
|
|
|
|
{
|
|
|
|
error: null,
|
|
|
|
result:
|
|
|
|
'3WE5w4B7v59x6qjyC4FbG2FEKYKQfvsJwqSxNVmtMjT8TQ31hsZieDHcSgqzxiAoTL56n2w5TncjqEKjLhtF4Vk',
|
|
|
|
},
|
|
|
|
]);
|
|
|
|
|
2020-09-10 00:43:32 -07:00
|
|
|
const transaction = new Transaction().add(
|
|
|
|
SystemProgram.createNonceAccount({
|
|
|
|
fromPubkey: from.publicKey,
|
|
|
|
noncePubkey: noncePubkey,
|
|
|
|
basePubkey: from.publicKey,
|
|
|
|
seed,
|
|
|
|
authorizedPubkey: from.publicKey,
|
|
|
|
lamports: minimumAmount,
|
|
|
|
}),
|
|
|
|
);
|
2020-07-08 05:46:16 -07:00
|
|
|
const nonceSignature = await connection.sendTransaction(transaction, [from], {
|
|
|
|
skipPreflight: true,
|
|
|
|
});
|
|
|
|
mockConfirmTransaction(nonceSignature);
|
2020-12-24 10:43:45 -08:00
|
|
|
await connection.confirmTransaction(nonceSignature, 'singleGossip');
|
2020-05-04 22:30:55 -07:00
|
|
|
|
|
|
|
mockRpc.push([
|
|
|
|
url,
|
|
|
|
{
|
|
|
|
method: 'getAccountInfo',
|
2020-08-15 21:38:11 -07:00
|
|
|
params: [
|
|
|
|
noncePubkey.toBase58(),
|
2020-12-24 10:43:45 -08:00
|
|
|
{encoding: 'base64', commitment: 'singleGossip'},
|
2020-08-15 21:38:11 -07:00
|
|
|
],
|
2020-05-04 22:30:55 -07:00
|
|
|
},
|
|
|
|
{
|
|
|
|
error: null,
|
|
|
|
result: {
|
|
|
|
context: {
|
|
|
|
slot: 11,
|
|
|
|
},
|
|
|
|
value: {
|
|
|
|
owner: '11111111111111111111111111111111',
|
|
|
|
lamports: minimumAmount,
|
|
|
|
data: expectedData(from.publicKey),
|
|
|
|
executable: false,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
]);
|
|
|
|
//
|
|
|
|
const nonceAccountData = await connection.getNonce(noncePubkey);
|
2020-04-05 01:18:45 -07:00
|
|
|
if (nonceAccountData === null) {
|
|
|
|
expect(nonceAccountData).not.toBeNull();
|
|
|
|
return;
|
|
|
|
}
|
2020-01-02 17:54:43 -08:00
|
|
|
expect(nonceAccountData.authorizedPubkey).toEqual(from.publicKey);
|
|
|
|
expect(bs58.decode(nonceAccountData.nonce).length).toBeGreaterThan(30);
|
|
|
|
});
|