From 9c8cc0bd24216f39bb9e04d3e679e446e9eee3fd Mon Sep 17 00:00:00 2001 From: Michael Vines Date: Mon, 22 Oct 2018 15:31:56 -0700 Subject: [PATCH] fix: wait for the next lastId before sending a new transaction --- web3.js/src/connection.js | 24 +++++++++++++++++++++++- web3.js/test/connection.test.js | 27 +++------------------------ web3.js/test/mockrpc/getlastid.js | 23 +++++++++++++++++++++++ web3.js/test/token-program.test.js | 15 +-------------- 4 files changed, 50 insertions(+), 39 deletions(-) create mode 100644 web3.js/test/mockrpc/getlastid.js diff --git a/web3.js/src/connection.js b/web3.js/src/connection.js index 91e1f1226c..8a2c86bd09 100644 --- a/web3.js/src/connection.js +++ b/web3.js/src/connection.js @@ -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 { - 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(); diff --git a/web3.js/test/connection.test.js b/web3.js/test/connection.test.js index ae1b086556..a639fa0233 100644 --- a/web3.js/test/connection.test.js +++ b/web3.js/test/connection.test.js @@ -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, { diff --git a/web3.js/test/mockrpc/getlastid.js b/web3.js/test/mockrpc/getlastid.js new file mode 100644 index 0000000000..07834637b8 --- /dev/null +++ b/web3.js/test/mockrpc/getlastid.js @@ -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(), + } + ]); +} diff --git a/web3.js/test/token-program.test.js b/web3.js/test/token-program.test.js index b08ff9ca15..ad4aa6fe98 100644 --- a/web3.js/test/token-program.test.js +++ b/web3.js/test/token-program.test.js @@ -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,