fix: wait for the next lastId before sending a new transaction
This commit is contained in:
parent
d9b98918b6
commit
9c8cc0bd24
|
@ -7,6 +7,7 @@ import {struct} from 'superstruct';
|
|||
|
||||
import {Transaction} from './transaction';
|
||||
import {PublicKey} from './publickey';
|
||||
import {sleep} from './util/sleep';
|
||||
import type {Account} from './account';
|
||||
import type {TransactionSignature, TransactionId} from './transaction';
|
||||
|
||||
|
@ -158,6 +159,7 @@ export type SignatureStatus = 'Confirmed' | 'SignatureNotFound' | 'ProgramRuntim
|
|||
*/
|
||||
export class Connection {
|
||||
_rpcRequest: RpcRequest;
|
||||
_lastId: null | TransactionId;
|
||||
|
||||
/**
|
||||
* Establish a JSON RPC connection
|
||||
|
@ -169,6 +171,7 @@ export class Connection {
|
|||
throw new Error('Connection endpoint not specified');
|
||||
}
|
||||
this._rpcRequest = createRpcRequest(endpoint);
|
||||
this._lastId = null;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -298,7 +301,26 @@ export class Connection {
|
|||
* Sign and send a transaction
|
||||
*/
|
||||
async sendTransaction(from: Account, transaction: Transaction): Promise<TransactionSignature> {
|
||||
transaction.lastId = await this.getLastId();
|
||||
|
||||
let attempts = 0;
|
||||
for (;;) {
|
||||
transaction.lastId = await this.getLastId();
|
||||
|
||||
// TODO: Waiting for the next lastId is really only necessary if a second
|
||||
// transaction with the raw input bytes as an in-flight transaction
|
||||
// is issued.
|
||||
if (this._lastId != transaction.lastId) {
|
||||
this._lastId = transaction.lastId;
|
||||
break;
|
||||
}
|
||||
if (attempts === 20) {
|
||||
throw new Error('Unable to obtain new last id');
|
||||
}
|
||||
// TODO: Add a pubsub notification for obtaining the next last id instead
|
||||
// of polling?
|
||||
await sleep(100);
|
||||
++attempts;
|
||||
}
|
||||
transaction.sign(from);
|
||||
|
||||
const wireTransaction = transaction.serialize();
|
||||
|
|
|
@ -6,6 +6,7 @@ import {
|
|||
SystemProgram,
|
||||
} from '../src';
|
||||
import {mockRpc, mockRpcEnabled} from './__mocks__/node-fetch';
|
||||
import {mockGetLastId} from './mockrpc/getlastid';
|
||||
import {url} from './url';
|
||||
|
||||
if (!mockRpcEnabled) {
|
||||
|
@ -117,18 +118,7 @@ test('get transaction count', async () => {
|
|||
test('get last Id', async () => {
|
||||
const connection = new Connection(url);
|
||||
|
||||
mockRpc.push([
|
||||
url,
|
||||
{
|
||||
method: 'getLastId',
|
||||
params: [],
|
||||
},
|
||||
{
|
||||
error: null,
|
||||
result: '2BjEqiiT43J6XskiHdz7aoocjPeWkCPiKD72SiFQsrA2',
|
||||
}
|
||||
]
|
||||
);
|
||||
mockGetLastId();
|
||||
|
||||
const lastId = await connection.getLastId();
|
||||
expect(lastId.length).toBeGreaterThanOrEqual(43);
|
||||
|
@ -283,18 +273,7 @@ test('transaction', async () => {
|
|||
await connection.requestAirdrop(accountTo.publicKey, 21);
|
||||
expect(await connection.getBalance(accountTo.publicKey)).toBe(21);
|
||||
|
||||
mockRpc.push([
|
||||
url,
|
||||
{
|
||||
method: 'getLastId',
|
||||
params: [],
|
||||
},
|
||||
{
|
||||
error: null,
|
||||
result: '2BjEqiiT43J6XskiHdz7aoocjPeWkCPiKD72SiFQsrA2',
|
||||
}
|
||||
]
|
||||
);
|
||||
mockGetLastId();
|
||||
mockRpc.push([
|
||||
url,
|
||||
{
|
||||
|
|
|
@ -0,0 +1,23 @@
|
|||
// @flow
|
||||
|
||||
import {
|
||||
Account,
|
||||
} from '../../src';
|
||||
import {url} from '../url';
|
||||
import {mockRpc} from '../__mocks__/node-fetch';
|
||||
|
||||
export function mockGetLastId() {
|
||||
const lastId = new Account();
|
||||
|
||||
mockRpc.push([
|
||||
url,
|
||||
{
|
||||
method: 'getLastId',
|
||||
params: [],
|
||||
},
|
||||
{
|
||||
error: null,
|
||||
result: lastId.publicKey.toBase58(),
|
||||
}
|
||||
]);
|
||||
}
|
|
@ -10,26 +10,13 @@ import {SYSTEM_TOKEN_PROGRAM_ID} from '../src/token-program';
|
|||
import {mockRpc, mockRpcEnabled} from './__mocks__/node-fetch';
|
||||
import {url} from './url';
|
||||
import {newAccountWithTokens} from './new-account-with-tokens';
|
||||
import {mockGetLastId} from './mockrpc/getlastid';
|
||||
|
||||
if (!mockRpcEnabled) {
|
||||
// The default of 5 seconds is too slow for live testing sometimes
|
||||
jest.setTimeout(10000);
|
||||
}
|
||||
|
||||
function mockGetLastId() {
|
||||
mockRpc.push([
|
||||
url,
|
||||
{
|
||||
method: 'getLastId',
|
||||
params: [],
|
||||
},
|
||||
{
|
||||
error: null,
|
||||
result: '2BjEqiiT43J6XskiHdz7aoocjPeWkCPiKD72SiFQsrA2',
|
||||
}
|
||||
]);
|
||||
}
|
||||
|
||||
function mockGetSignatureStatus(result: string = 'Confirmed') {
|
||||
mockRpc.push([
|
||||
url,
|
||||
|
|
Loading…
Reference in New Issue