From ead990a734e0caf0ce0e5d0297c487756894acf2 Mon Sep 17 00:00:00 2001 From: Jacob Evans Date: Wed, 31 Jan 2018 16:19:47 +1100 Subject: Nonce tracker subprovider Caches the nonce when a request to getTransactionCount is made and increments the pending nonce after successful transactions --- packages/subproviders/src/globals.d.ts | 21 +++ packages/subproviders/src/index.ts | 1 + .../subproviders/src/subproviders/nonce_tracker.ts | 112 ++++++++++++ .../test/unit/nonce_tracker_subprovider_test.ts | 195 +++++++++++++++++++++ 4 files changed, 329 insertions(+) create mode 100644 packages/subproviders/src/subproviders/nonce_tracker.ts create mode 100644 packages/subproviders/test/unit/nonce_tracker_subprovider_test.ts diff --git a/packages/subproviders/src/globals.d.ts b/packages/subproviders/src/globals.d.ts index 53457fa24..595bae89e 100644 --- a/packages/subproviders/src/globals.d.ts +++ b/packages/subproviders/src/globals.d.ts @@ -1,3 +1,4 @@ + declare module 'dirty-chai'; declare module 'es6-promisify'; @@ -13,7 +14,9 @@ declare module 'ethereumjs-tx' { public r: Buffer; public s: Buffer; public v: Buffer; + public nonce: Buffer; public serialize(): Buffer; + public getSenderAddress(): Buffer; constructor(txParams: any); } export = EthereumTx; @@ -97,6 +100,24 @@ declare module 'web3-provider-engine' { } export = Web3ProviderEngine; } +declare module 'web3-provider-engine/util/rpc-cache-utils' { + class ProviderEngineRpcUtils { + public static blockTagForPayload(payload: any): string|null; + } + export = ProviderEngineRpcUtils; +} +declare module 'web3-provider-engine/subproviders/fixture' { + import * as Web3 from 'web3'; + class FixtureSubprovider { + constructor(staticResponses: any); + public handleRequest( + payload: Web3.JSONRPCRequestPayload, + next: () => void, + end: (err: Error | null, data?: any) => void, + ): void; + } + export = FixtureSubprovider; +} // hdkey declarations declare module 'hdkey' { diff --git a/packages/subproviders/src/index.ts b/packages/subproviders/src/index.ts index 720c4362f..4b3be4efd 100644 --- a/packages/subproviders/src/index.ts +++ b/packages/subproviders/src/index.ts @@ -9,6 +9,7 @@ import { LedgerEthereumClient } from './types'; export { InjectedWeb3Subprovider } from './subproviders/injected_web3'; export { RedundantRPCSubprovider } from './subproviders/redundant_rpc'; export { LedgerSubprovider } from './subproviders/ledger'; +export { NonceTrackerSubprovider } from './subproviders/nonce_tracker'; export { ECSignature, LedgerWalletSubprovider, LedgerCommunicationClient } from './types'; /** diff --git a/packages/subproviders/src/subproviders/nonce_tracker.ts b/packages/subproviders/src/subproviders/nonce_tracker.ts new file mode 100644 index 000000000..540a91771 --- /dev/null +++ b/packages/subproviders/src/subproviders/nonce_tracker.ts @@ -0,0 +1,112 @@ +import { promisify } from '@0xproject/utils'; +import * as _ from 'lodash'; + +import EthereumTx = require('ethereumjs-tx'); +import ethUtil = require('ethereumjs-util'); +import providerEngineUtils = require('web3-provider-engine/util/rpc-cache-utils'); + +import { JSONRPCPayload } from '../types'; + +import { Subprovider } from './subprovider'; + +const NONCE_TOO_LOW_ERROR_MESSAGE = 'Transaction nonce is too low'; + +export class NonceTrackerSubprovider extends Subprovider { + private _nonceCache: { [address: string]: string } = {}; + private static _reconstructTransaction(payload: JSONRPCPayload): EthereumTx { + const raw = payload.params[0]; + const transactionData = ethUtil.stripHexPrefix(raw); + const rawData = new Buffer(transactionData, 'hex'); + return new EthereumTx(rawData); + } + private static _determineAddress(payload: JSONRPCPayload): string { + switch (payload.method) { + case 'eth_getTransactionCount': + return payload.params[0].toLowerCase(); + case 'eth_sendRawTransaction': + const transaction = NonceTrackerSubprovider._reconstructTransaction(payload); + return `0x${transaction.getSenderAddress().toString('hex')}`.toLowerCase(); + default: + throw new Error('Invalid Method'); + } + } + constructor() { + super(); + } + // tslint:disable-next-line:async-suffix + public async handleRequest( + payload: JSONRPCPayload, + next: (callback?: (err: Error | null, result: any, cb: any) => void) => void, + end: (err: Error | null, data?: any) => void, + ): Promise { + switch (payload.method) { + case 'eth_getTransactionCount': + const blockTag = providerEngineUtils.blockTagForPayload(payload); + if (!_.isNull(blockTag) && blockTag === 'pending') { + const address = NonceTrackerSubprovider._determineAddress(payload); + const cachedResult = this._nonceCache[address]; + if (cachedResult) { + end(null, cachedResult); + return; + } else { + next((requestError: Error | null, requestResult: any, cb: any) => { + if (_.isNull(requestError)) { + this._nonceCache[address] = requestResult as string; + } + cb(); + return; + }); + return; + } + } else { + next(); + return; + } + case 'eth_sendRawTransaction': + return next(async (sendTransactionError: Error | null, txResult: any, cb: any) => { + if (_.isNull(sendTransactionError)) { + this._handleSuccessfulTransaction(payload); + } else { + await this._handleSendTransactionErrorAsync(payload, sendTransactionError); + } + cb(); + }); + default: + return next(); + } + } + private _handleSuccessfulTransaction(payload: JSONRPCPayload): void { + const address = NonceTrackerSubprovider._determineAddress(payload); + const transaction = NonceTrackerSubprovider._reconstructTransaction(payload); + // Increment the nonce from the previous successfully submitted transaction + let nonce = ethUtil.bufferToInt(transaction.nonce); + nonce++; + let nextHexNonce = nonce.toString(16); + if (nextHexNonce.length % 2) { + nextHexNonce = `0${nextHexNonce}`; + } + nextHexNonce = `0x${nextHexNonce}`; + this._nonceCache[address] = nextHexNonce; + } + private async _handleSendTransactionErrorAsync(payload: JSONRPCPayload, err: Error): Promise { + const address = NonceTrackerSubprovider._determineAddress(payload); + if (this._nonceCache[address]) { + if (_.includes(err.message, NONCE_TOO_LOW_ERROR_MESSAGE)) { + await this._handleNonceTooLowErrorAsync(address); + } + } + } + private async _handleNonceTooLowErrorAsync(address: string): Promise { + const oldNonceInt = ethUtil.bufferToInt(new Buffer(this._nonceCache[address], 'hex')); + delete this._nonceCache[address]; + const nonceResult = await this.emitPayloadAsync({ + method: 'eth_getTransactionCount', + params: [address, 'pending'], + }); + const nonce = nonceResult.result; + const latestNonceInt = ethUtil.bufferToInt(new Buffer(nonce, 'hex')); + if (latestNonceInt > oldNonceInt) { + this._nonceCache[address] = nonce; + } + } +} diff --git a/packages/subproviders/test/unit/nonce_tracker_subprovider_test.ts b/packages/subproviders/test/unit/nonce_tracker_subprovider_test.ts new file mode 100644 index 000000000..a99f1f9fb --- /dev/null +++ b/packages/subproviders/test/unit/nonce_tracker_subprovider_test.ts @@ -0,0 +1,195 @@ +import * as chai from 'chai'; +import * as _ from 'lodash'; +import Web3 = require('web3'); +import Web3ProviderEngine = require('web3-provider-engine'); +import FixtureSubprovider = require('web3-provider-engine/subproviders/fixture'); + +import promisify = require('es6-promisify'); +import EthereumTx = require('ethereumjs-tx'); + +import { NonceTrackerSubprovider } from '../../src'; +import { DoneCallback } from '../../src/types'; +import { chaiSetup } from '../chai_setup'; +import { reportCallbackErrors } from '../utils/report_callback_errors'; + +import { Subprovider } from '../../src/subproviders/subprovider'; + +const expect = chai.expect; +chaiSetup.configure(); + +describe('NonceTrackerSubprovider', () => { + let provider: Web3ProviderEngine; + it('successfully caches the transaction count', async () => { + provider = new Web3ProviderEngine(); + let called = false; + const nonceTrackerSubprovider = new NonceTrackerSubprovider(); + provider.addProvider(nonceTrackerSubprovider); + provider.addProvider(new FixtureSubprovider({ + 'eth_getBlockByNumber': '0x01', + 'eth_getTransactionCount': (data: any, next: any, end: any) => { + if (called) { + return end(null, '0x99'); + } else { + called = true; + end(null, '0x01'); + } + }, + })); + provider.start(); + + const payload = { + jsonrpc: '2.0', + method: 'eth_getTransactionCount', + params: ['0x0', 'pending'], + id: 1, + }; + + const response = await promisify(provider.sendAsync, provider)(payload); + expect(response.result).to.be.eq('0x01'); + const secondResponse = await promisify(provider.sendAsync, provider)(payload); + expect(secondResponse.result).to.be.eq('0x01'); + }); + it('does not cache the result for latest transaction count', async () => { + provider = new Web3ProviderEngine(); + let called = false; + const nonceTrackerSubprovider = new NonceTrackerSubprovider(); + provider.addProvider(nonceTrackerSubprovider); + provider.addProvider(new FixtureSubprovider({ + 'eth_getBlockByNumber': '0x01', + 'eth_getTransactionCount': (data: any, next: any, end: any) => { + if (called) { + return end(null, '0x99'); + } else { + called = true; + end(null, '0x01'); + } + }, + })); + provider.start(); + + const payload = { + jsonrpc: '2.0', + method: 'eth_getTransactionCount', + params: ['0x0', 'latest'], + id: 1, + }; + + const response = await promisify(provider.sendAsync, provider)(payload); + expect(response.result).to.be.eq('0x01'); + const secondResponse = await promisify(provider.sendAsync, provider)(payload); + expect(secondResponse.result).to.be.eq('0x99'); + }); + it('clears the cache on a Nonce Too Low Error', async () => { + provider = new Web3ProviderEngine(); + let called = false; + const nonceTrackerSubprovider = new NonceTrackerSubprovider(); + provider.addProvider(nonceTrackerSubprovider); + provider.addProvider(new FixtureSubprovider({ + 'eth_getBlockByNumber': '0x01', + 'eth_getTransactionCount': (data: any, next: any, end: any) => { + if (called) { + return end(null, '0x99'); + } else { + called = true; + end(null, '0x01'); + } + }, + 'eth_sendRawTransaction': (data: any, next: any, end: any) => { + end(new Error('Transaction nonce is too low')); + }, + })); + provider.start(); + + const noncePayload = { + jsonrpc: '2.0', + method: 'eth_getTransactionCount', + params: ['0x1f36f546477cda21bf2296c50976f2740247906f', 'pending'], + id: 1, + }; + const txParams = [ + '0x', + '0x09184e72a000', + '0x2710', + '0x0000000000000000000000000000000000000000', + '0x', + '0x7f7465737432000000000000000000000000000000000000000000000000000000600057', + '0x1c', + '0x5e1d3a76fbf824220eafc8c79ad578ad2b67d01b0c2425eb1f1347e8f50882ab', + '0x5bd428537f05f9830e93792f90ea6a3e2d1ee84952dd96edbae9f658f831ab13' + ]; + + const transaction = new EthereumTx(txParams); + const txPayload = { + jsonrpc: '2.0', + method: 'eth_sendRawTransaction', + params: [transaction.serialize()], + id: 1, + }; + + const response = await promisify(provider.sendAsync, provider)(noncePayload); + expect(response.result).to.be.eq('0x01'); + const secondResponse = await promisify(provider.sendAsync, provider)(noncePayload); + expect(secondResponse.result).to.be.eq('0x01'); + try { + const txResponse = await promisify(provider.sendAsync, provider)(txPayload); + } catch (err) { + const thirdResponse = await promisify(provider.sendAsync, provider)(noncePayload); + expect(thirdResponse.result).to.be.eq('0x99'); + } + }); + it('increments the used nonce', async () => { + provider = new Web3ProviderEngine(); + let called = false; + const nonceTrackerSubprovider = new NonceTrackerSubprovider(); + provider.addProvider(nonceTrackerSubprovider); + provider.addProvider(new FixtureSubprovider({ + 'eth_getBlockByNumber': '0x01', + 'eth_getTransactionCount': (data: any, next: any, end: any) => { + if (called) { + return end(null, '0x99'); + } else { + called = true; + end(null, '0x00'); + } + }, + 'eth_sendRawTransaction': (data: any, next: any, end: any) => { + end(null); + }, + })); + provider.start(); + + const noncePayload = { + jsonrpc: '2.0', + method: 'eth_getTransactionCount', + params: ['0x1f36f546477cda21bf2296c50976f2740247906f', 'pending'], + id: 1, + }; + const txParams = [ + '0x', + '0x09184e72a000', + '0x2710', + '0x0000000000000000000000000000000000000000', + '0x', + '0x7f7465737432000000000000000000000000000000000000000000000000000000600057', + '0x1c', + '0x5e1d3a76fbf824220eafc8c79ad578ad2b67d01b0c2425eb1f1347e8f50882ab', + '0x5bd428537f05f9830e93792f90ea6a3e2d1ee84952dd96edbae9f658f831ab13' + ]; + + const transaction = new EthereumTx(txParams); + const txPayload = { + jsonrpc: '2.0', + method: 'eth_sendRawTransaction', + params: [transaction.serialize()], + id: 1, + }; + + const response = await promisify(provider.sendAsync, provider)(noncePayload); + expect(response.result).to.be.eq('0x00'); + const secondResponse = await promisify(provider.sendAsync, provider)(noncePayload); + expect(secondResponse.result).to.be.eq('0x00'); + const txResponse = await promisify(provider.sendAsync, provider)(txPayload); + const thirdResponse = await promisify(provider.sendAsync, provider)(noncePayload); + expect(thirdResponse.result).to.be.eq('0x01'); + }); +}); -- cgit From 58dd90b7b7408a04a39e2e643c77bbf86859df1d Mon Sep 17 00:00:00 2001 From: Jacob Evans Date: Wed, 31 Jan 2018 16:23:51 +1100 Subject: Prettify --- packages/subproviders/src/globals.d.ts | 1 - .../subproviders/src/subproviders/nonce_tracker.ts | 11 +- .../test/unit/nonce_tracker_subprovider_test.ts | 121 +++++++++++---------- 3 files changed, 65 insertions(+), 68 deletions(-) diff --git a/packages/subproviders/src/globals.d.ts b/packages/subproviders/src/globals.d.ts index 595bae89e..325dc27ed 100644 --- a/packages/subproviders/src/globals.d.ts +++ b/packages/subproviders/src/globals.d.ts @@ -1,4 +1,3 @@ - declare module 'dirty-chai'; declare module 'es6-promisify'; diff --git a/packages/subproviders/src/subproviders/nonce_tracker.ts b/packages/subproviders/src/subproviders/nonce_tracker.ts index 540a91771..560f2dd68 100644 --- a/packages/subproviders/src/subproviders/nonce_tracker.ts +++ b/packages/subproviders/src/subproviders/nonce_tracker.ts @@ -1,4 +1,3 @@ -import { promisify } from '@0xproject/utils'; import * as _ from 'lodash'; import EthereumTx = require('ethereumjs-tx'); @@ -46,21 +45,17 @@ export class NonceTrackerSubprovider extends Subprovider { const address = NonceTrackerSubprovider._determineAddress(payload); const cachedResult = this._nonceCache[address]; if (cachedResult) { - end(null, cachedResult); - return; + return end(null, cachedResult); } else { - next((requestError: Error | null, requestResult: any, cb: any) => { + return next((requestError: Error | null, requestResult: any, cb: any) => { if (_.isNull(requestError)) { this._nonceCache[address] = requestResult as string; } cb(); - return; }); - return; } } else { - next(); - return; + return next(); } case 'eth_sendRawTransaction': return next(async (sendTransactionError: Error | null, txResult: any, cb: any) => { diff --git a/packages/subproviders/test/unit/nonce_tracker_subprovider_test.ts b/packages/subproviders/test/unit/nonce_tracker_subprovider_test.ts index a99f1f9fb..9bb8268cb 100644 --- a/packages/subproviders/test/unit/nonce_tracker_subprovider_test.ts +++ b/packages/subproviders/test/unit/nonce_tracker_subprovider_test.ts @@ -1,6 +1,5 @@ import * as chai from 'chai'; import * as _ from 'lodash'; -import Web3 = require('web3'); import Web3ProviderEngine = require('web3-provider-engine'); import FixtureSubprovider = require('web3-provider-engine/subproviders/fixture'); @@ -8,11 +7,7 @@ import promisify = require('es6-promisify'); import EthereumTx = require('ethereumjs-tx'); import { NonceTrackerSubprovider } from '../../src'; -import { DoneCallback } from '../../src/types'; import { chaiSetup } from '../chai_setup'; -import { reportCallbackErrors } from '../utils/report_callback_errors'; - -import { Subprovider } from '../../src/subproviders/subprovider'; const expect = chai.expect; chaiSetup.configure(); @@ -24,17 +19,19 @@ describe('NonceTrackerSubprovider', () => { let called = false; const nonceTrackerSubprovider = new NonceTrackerSubprovider(); provider.addProvider(nonceTrackerSubprovider); - provider.addProvider(new FixtureSubprovider({ - 'eth_getBlockByNumber': '0x01', - 'eth_getTransactionCount': (data: any, next: any, end: any) => { - if (called) { - return end(null, '0x99'); - } else { - called = true; - end(null, '0x01'); - } - }, - })); + provider.addProvider( + new FixtureSubprovider({ + eth_getBlockByNumber: '0x01', + eth_getTransactionCount: (data: any, next: any, end: any) => { + if (called) { + return end(null, '0x99'); + } else { + called = true; + end(null, '0x01'); + } + }, + }), + ); provider.start(); const payload = { @@ -54,17 +51,19 @@ describe('NonceTrackerSubprovider', () => { let called = false; const nonceTrackerSubprovider = new NonceTrackerSubprovider(); provider.addProvider(nonceTrackerSubprovider); - provider.addProvider(new FixtureSubprovider({ - 'eth_getBlockByNumber': '0x01', - 'eth_getTransactionCount': (data: any, next: any, end: any) => { - if (called) { - return end(null, '0x99'); - } else { - called = true; - end(null, '0x01'); - } - }, - })); + provider.addProvider( + new FixtureSubprovider({ + eth_getBlockByNumber: '0x01', + eth_getTransactionCount: (data: any, next: any, end: any) => { + if (called) { + return end(null, '0x99'); + } else { + called = true; + end(null, '0x01'); + } + }, + }), + ); provider.start(); const payload = { @@ -84,20 +83,22 @@ describe('NonceTrackerSubprovider', () => { let called = false; const nonceTrackerSubprovider = new NonceTrackerSubprovider(); provider.addProvider(nonceTrackerSubprovider); - provider.addProvider(new FixtureSubprovider({ - 'eth_getBlockByNumber': '0x01', - 'eth_getTransactionCount': (data: any, next: any, end: any) => { - if (called) { - return end(null, '0x99'); - } else { - called = true; - end(null, '0x01'); - } - }, - 'eth_sendRawTransaction': (data: any, next: any, end: any) => { - end(new Error('Transaction nonce is too low')); - }, - })); + provider.addProvider( + new FixtureSubprovider({ + eth_getBlockByNumber: '0x01', + eth_getTransactionCount: (data: any, next: any, end: any) => { + if (called) { + return end(null, '0x99'); + } else { + called = true; + end(null, '0x01'); + } + }, + eth_sendRawTransaction: (data: any, next: any, end: any) => { + end(new Error('Transaction nonce is too low')); + }, + }), + ); provider.start(); const noncePayload = { @@ -115,7 +116,7 @@ describe('NonceTrackerSubprovider', () => { '0x7f7465737432000000000000000000000000000000000000000000000000000000600057', '0x1c', '0x5e1d3a76fbf824220eafc8c79ad578ad2b67d01b0c2425eb1f1347e8f50882ab', - '0x5bd428537f05f9830e93792f90ea6a3e2d1ee84952dd96edbae9f658f831ab13' + '0x5bd428537f05f9830e93792f90ea6a3e2d1ee84952dd96edbae9f658f831ab13', ]; const transaction = new EthereumTx(txParams); @@ -131,7 +132,7 @@ describe('NonceTrackerSubprovider', () => { const secondResponse = await promisify(provider.sendAsync, provider)(noncePayload); expect(secondResponse.result).to.be.eq('0x01'); try { - const txResponse = await promisify(provider.sendAsync, provider)(txPayload); + await promisify(provider.sendAsync, provider)(txPayload); } catch (err) { const thirdResponse = await promisify(provider.sendAsync, provider)(noncePayload); expect(thirdResponse.result).to.be.eq('0x99'); @@ -142,20 +143,22 @@ describe('NonceTrackerSubprovider', () => { let called = false; const nonceTrackerSubprovider = new NonceTrackerSubprovider(); provider.addProvider(nonceTrackerSubprovider); - provider.addProvider(new FixtureSubprovider({ - 'eth_getBlockByNumber': '0x01', - 'eth_getTransactionCount': (data: any, next: any, end: any) => { - if (called) { - return end(null, '0x99'); - } else { - called = true; - end(null, '0x00'); - } - }, - 'eth_sendRawTransaction': (data: any, next: any, end: any) => { - end(null); - }, - })); + provider.addProvider( + new FixtureSubprovider({ + eth_getBlockByNumber: '0x01', + eth_getTransactionCount: (data: any, next: any, end: any) => { + if (called) { + return end(null, '0x99'); + } else { + called = true; + end(null, '0x00'); + } + }, + eth_sendRawTransaction: (data: any, next: any, end: any) => { + end(null); + }, + }), + ); provider.start(); const noncePayload = { @@ -173,7 +176,7 @@ describe('NonceTrackerSubprovider', () => { '0x7f7465737432000000000000000000000000000000000000000000000000000000600057', '0x1c', '0x5e1d3a76fbf824220eafc8c79ad578ad2b67d01b0c2425eb1f1347e8f50882ab', - '0x5bd428537f05f9830e93792f90ea6a3e2d1ee84952dd96edbae9f658f831ab13' + '0x5bd428537f05f9830e93792f90ea6a3e2d1ee84952dd96edbae9f658f831ab13', ]; const transaction = new EthereumTx(txParams); @@ -188,7 +191,7 @@ describe('NonceTrackerSubprovider', () => { expect(response.result).to.be.eq('0x00'); const secondResponse = await promisify(provider.sendAsync, provider)(noncePayload); expect(secondResponse.result).to.be.eq('0x00'); - const txResponse = await promisify(provider.sendAsync, provider)(txPayload); + await promisify(provider.sendAsync, provider)(txPayload); const thirdResponse = await promisify(provider.sendAsync, provider)(noncePayload); expect(thirdResponse.result).to.be.eq('0x01'); }); -- cgit From d635559a304f531314a89c91eb860a0d517404b3 Mon Sep 17 00:00:00 2001 From: Jacob Evans Date: Thu, 1 Feb 2018 10:22:21 +1100 Subject: Readability and prettier --- packages/subproviders/src/globals.d.ts | 2 +- .../subproviders/src/subproviders/nonce_tracker.ts | 22 ++++++++++------------ 2 files changed, 11 insertions(+), 13 deletions(-) diff --git a/packages/subproviders/src/globals.d.ts b/packages/subproviders/src/globals.d.ts index 325dc27ed..6f344dcd3 100644 --- a/packages/subproviders/src/globals.d.ts +++ b/packages/subproviders/src/globals.d.ts @@ -101,7 +101,7 @@ declare module 'web3-provider-engine' { } declare module 'web3-provider-engine/util/rpc-cache-utils' { class ProviderEngineRpcUtils { - public static blockTagForPayload(payload: any): string|null; + public static blockTagForPayload(payload: any): string | null; } export = ProviderEngineRpcUtils; } diff --git a/packages/subproviders/src/subproviders/nonce_tracker.ts b/packages/subproviders/src/subproviders/nonce_tracker.ts index 560f2dd68..a1e499629 100644 --- a/packages/subproviders/src/subproviders/nonce_tracker.ts +++ b/packages/subproviders/src/subproviders/nonce_tracker.ts @@ -10,12 +10,17 @@ import { Subprovider } from './subprovider'; const NONCE_TOO_LOW_ERROR_MESSAGE = 'Transaction nonce is too low'; +export type OptionalNextCallback = (callback?: (err: Error | null, result: any, cb: any) => void) => void; +export type ErrorCallback = (err: Error | null, data?: any) => void; + export class NonceTrackerSubprovider extends Subprovider { private _nonceCache: { [address: string]: string } = {}; private static _reconstructTransaction(payload: JSONRPCPayload): EthereumTx { const raw = payload.params[0]; - const transactionData = ethUtil.stripHexPrefix(raw); - const rawData = new Buffer(transactionData, 'hex'); + if (_.isUndefined(raw)) { + throw new Error('Invalid transaction: empty parameters'); + } + const rawData = ethUtil.toBuffer(raw); return new EthereumTx(rawData); } private static _determineAddress(payload: JSONRPCPayload): string { @@ -26,25 +31,18 @@ export class NonceTrackerSubprovider extends Subprovider { const transaction = NonceTrackerSubprovider._reconstructTransaction(payload); return `0x${transaction.getSenderAddress().toString('hex')}`.toLowerCase(); default: - throw new Error('Invalid Method'); + throw new Error(`Invalid Method: ${payload.method}`); } } - constructor() { - super(); - } // tslint:disable-next-line:async-suffix - public async handleRequest( - payload: JSONRPCPayload, - next: (callback?: (err: Error | null, result: any, cb: any) => void) => void, - end: (err: Error | null, data?: any) => void, - ): Promise { + public async handleRequest(payload: JSONRPCPayload, next: OptionalNextCallback, end: ErrorCallback): Promise { switch (payload.method) { case 'eth_getTransactionCount': const blockTag = providerEngineUtils.blockTagForPayload(payload); if (!_.isNull(blockTag) && blockTag === 'pending') { const address = NonceTrackerSubprovider._determineAddress(payload); const cachedResult = this._nonceCache[address]; - if (cachedResult) { + if (!_.isUndefined(cachedResult)) { return end(null, cachedResult); } else { return next((requestError: Error | null, requestResult: any, cb: any) => { -- cgit From b7af597668668124a4bc28f2e621ef5d07d4bd5a Mon Sep 17 00:00:00 2001 From: Jacob Evans Date: Fri, 2 Feb 2018 10:37:07 +1100 Subject: Update changelog --- packages/subproviders/CHANGELOG.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/packages/subproviders/CHANGELOG.md b/packages/subproviders/CHANGELOG.md index 0469150c0..512e8ce8b 100644 --- a/packages/subproviders/CHANGELOG.md +++ b/packages/subproviders/CHANGELOG.md @@ -1,6 +1,10 @@ # CHANGELOG -## v0.4.0 - _January 28, 2017_ +## v0.4.1 - _Febuary 2, 2018_ + + * Added NonceTrackerSubprovider + +## v0.4.0 - _January 28, 2018_ * Return a transaction hash from `_sendTransactionAsync` (#303) -- cgit From 76eb1e9e7ff771a256b0ddeeabe2dc10e3861d14 Mon Sep 17 00:00:00 2001 From: Jacob Evans Date: Fri, 2 Feb 2018 11:26:49 +1100 Subject: Test faucets to use new NonceTracker --- packages/testnet-faucets/Dockerfile | 1 + packages/testnet-faucets/src/ts/handler.ts | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/testnet-faucets/Dockerfile b/packages/testnet-faucets/Dockerfile index 6d6ddc192..57d72049b 100644 --- a/packages/testnet-faucets/Dockerfile +++ b/packages/testnet-faucets/Dockerfile @@ -2,6 +2,7 @@ FROM node WORKDIR /src +RUN apt-get -qq update && apt-get install -y libhidapi-dev libusb-1.0-0-dev COPY package.json . RUN npm i RUN npm install forever -g diff --git a/packages/testnet-faucets/src/ts/handler.ts b/packages/testnet-faucets/src/ts/handler.ts index bf5b3e81e..121112fd3 100644 --- a/packages/testnet-faucets/src/ts/handler.ts +++ b/packages/testnet-faucets/src/ts/handler.ts @@ -1,9 +1,9 @@ +import { NonceTrackerSubprovider } from '@0xproject/subproviders'; import { addressUtils } from '@0xproject/utils'; import * as express from 'express'; import * as _ from 'lodash'; import ProviderEngine = require('web3-provider-engine'); import HookedWalletSubprovider = require('web3-provider-engine/subproviders/hooked-wallet'); -import NonceSubprovider = require('web3-provider-engine/subproviders/nonce-tracker'); import RpcSubprovider = require('web3-provider-engine/subproviders/rpc'); import { EtherRequestQueue } from './ether_request_queue'; @@ -96,7 +96,7 @@ export class Handler { // tslint:disable-next-line:prefer-function-over-method private _createProviderEngine(rpcUrl: string) { const engine = new ProviderEngine(); - engine.addProvider(new NonceSubprovider()); + engine.addProvider(new NonceTrackerSubprovider()); engine.addProvider(new HookedWalletSubprovider(idManagement)); engine.addProvider( new RpcSubprovider({ -- cgit From 2eccb28dee6ad16f8b4a73102d36463067be8262 Mon Sep 17 00:00:00 2001 From: Jacob Evans Date: Thu, 1 Feb 2018 17:08:19 -0800 Subject: Enable CIRCLECI and declare web3 --- packages/testnet-faucets/Dockerfile | 1 + packages/testnet-faucets/package.json | 1 + packages/testnet-faucets/src/ts/global.d.ts | 12 ++++++++++++ 3 files changed, 14 insertions(+) diff --git a/packages/testnet-faucets/Dockerfile b/packages/testnet-faucets/Dockerfile index 57d72049b..346f461d8 100644 --- a/packages/testnet-faucets/Dockerfile +++ b/packages/testnet-faucets/Dockerfile @@ -3,6 +3,7 @@ FROM node WORKDIR /src RUN apt-get -qq update && apt-get install -y libhidapi-dev libusb-1.0-0-dev +ENV CIRCLECI=true COPY package.json . RUN npm i RUN npm install forever -g diff --git a/packages/testnet-faucets/package.json b/packages/testnet-faucets/package.json index f05899896..964401a67 100644 --- a/packages/testnet-faucets/package.json +++ b/packages/testnet-faucets/package.json @@ -16,6 +16,7 @@ "dependencies": { "0x.js": "^0.31.1", "@0xproject/utils": "^0.2.4", + "@0xproject/subproviders": "^0.3.5", "body-parser": "^1.17.1", "ethereumjs-tx": "^1.3.3", "express": "^4.15.2", diff --git a/packages/testnet-faucets/src/ts/global.d.ts b/packages/testnet-faucets/src/ts/global.d.ts index 97cd35680..a790366fb 100644 --- a/packages/testnet-faucets/src/ts/global.d.ts +++ b/packages/testnet-faucets/src/ts/global.d.ts @@ -24,3 +24,15 @@ declare module 'ethereumjs-tx' { } export = EthereumTx; } + +declare module 'web3-provider-engine' { + class Web3ProviderEngine { + public on(event: string, handler: () => void): void; + public send(payload: any): void; + public sendAsync(payload: any, callback: (error: any, response: any) => void): void; + public addProvider(provider: any): void; + public start(): void; + public stop(): void; + } + export = Web3ProviderEngine; +} \ No newline at end of file -- cgit From 48aa1ad57d91acba93c445c14177cb9e318974d8 Mon Sep 17 00:00:00 2001 From: Jacob Evans Date: Thu, 1 Feb 2018 18:43:32 -0800 Subject: Remove double declaration --- packages/testnet-faucets/src/ts/global.d.ts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/testnet-faucets/src/ts/global.d.ts b/packages/testnet-faucets/src/ts/global.d.ts index a790366fb..cdd624b1c 100644 --- a/packages/testnet-faucets/src/ts/global.d.ts +++ b/packages/testnet-faucets/src/ts/global.d.ts @@ -1,8 +1,4 @@ declare module 'rollbar'; -declare module 'web3-provider-engine'; -declare module 'web3-provider-engine/subproviders/rpc'; -declare module 'web3-provider-engine/subproviders/nonce-tracker'; -declare module 'web3-provider-engine/subproviders/hooked-wallet'; declare module '*.json' { const json: any; @@ -35,4 +31,8 @@ declare module 'web3-provider-engine' { public stop(): void; } export = Web3ProviderEngine; -} \ No newline at end of file +} + +declare module 'web3-provider-engine/subproviders/rpc'; +declare module 'web3-provider-engine/subproviders/nonce-tracker'; +declare module 'web3-provider-engine/subproviders/hooked-wallet'; -- cgit From dae6f28f8ad11358048a72a11ba4f8172092a1b0 Mon Sep 17 00:00:00 2001 From: Jacob Evans Date: Fri, 2 Feb 2018 15:07:10 -0800 Subject: Disable linter for multiple class declarations --- packages/testnet-faucets/src/ts/global.d.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/testnet-faucets/src/ts/global.d.ts b/packages/testnet-faucets/src/ts/global.d.ts index cdd624b1c..b9188bbf6 100644 --- a/packages/testnet-faucets/src/ts/global.d.ts +++ b/packages/testnet-faucets/src/ts/global.d.ts @@ -21,6 +21,7 @@ declare module 'ethereumjs-tx' { export = EthereumTx; } +/* tslint:disable */ declare module 'web3-provider-engine' { class Web3ProviderEngine { public on(event: string, handler: () => void): void; @@ -32,6 +33,7 @@ declare module 'web3-provider-engine' { } export = Web3ProviderEngine; } +/* tslint:enable */ declare module 'web3-provider-engine/subproviders/rpc'; declare module 'web3-provider-engine/subproviders/nonce-tracker'; -- cgit From fc3058c1e2fdf9a11eedd3d4c775d54fbf61b6c9 Mon Sep 17 00:00:00 2001 From: Jacob Evans Date: Mon, 5 Feb 2018 14:27:58 -0800 Subject: Remove re-fetch of transaction count on error --- packages/subproviders/CHANGELOG.md | 2 +- packages/subproviders/src/subproviders/ledger.ts | 2 + .../subproviders/src/subproviders/nonce_tracker.ts | 56 ++++++++++------------ .../subproviders/src/subproviders/redundant_rpc.ts | 1 + packages/subproviders/src/types.ts | 13 +++++ 5 files changed, 41 insertions(+), 33 deletions(-) diff --git a/packages/subproviders/CHANGELOG.md b/packages/subproviders/CHANGELOG.md index 512e8ce8b..8adaa1c08 100644 --- a/packages/subproviders/CHANGELOG.md +++ b/packages/subproviders/CHANGELOG.md @@ -2,7 +2,7 @@ ## v0.4.1 - _Febuary 2, 2018_ - * Added NonceTrackerSubprovider + * Added NonceTrackerSubprovider (#355) ## v0.4.0 - _January 28, 2018_ diff --git a/packages/subproviders/src/subproviders/ledger.ts b/packages/subproviders/src/subproviders/ledger.ts index 7267a793e..5966a88bb 100644 --- a/packages/subproviders/src/subproviders/ledger.ts +++ b/packages/subproviders/src/subproviders/ledger.ts @@ -60,6 +60,8 @@ export class LedgerSubprovider extends Subprovider { public setPathIndex(pathIndex: number) { this._derivationPathIndex = pathIndex; } + // Required to implement this public interface which doesn't conform to our linting rule. + // tslint:disable-next-line:async-suffix public async handleRequest( payload: Web3.JSONRPCRequestPayload, next: () => void, diff --git a/packages/subproviders/src/subproviders/nonce_tracker.ts b/packages/subproviders/src/subproviders/nonce_tracker.ts index a1e499629..2f94ea581 100644 --- a/packages/subproviders/src/subproviders/nonce_tracker.ts +++ b/packages/subproviders/src/subproviders/nonce_tracker.ts @@ -4,42 +4,49 @@ import EthereumTx = require('ethereumjs-tx'); import ethUtil = require('ethereumjs-util'); import providerEngineUtils = require('web3-provider-engine/util/rpc-cache-utils'); -import { JSONRPCPayload } from '../types'; +import { + BlockParamLiteral, + ErrorCallback, + JSONRPCPayload, + NonceSubproviderErrors, + OptionalNextCallback, +} from '../types'; import { Subprovider } from './subprovider'; const NONCE_TOO_LOW_ERROR_MESSAGE = 'Transaction nonce is too low'; - -export type OptionalNextCallback = (callback?: (err: Error | null, result: any, cb: any) => void) => void; -export type ErrorCallback = (err: Error | null, data?: any) => void; - export class NonceTrackerSubprovider extends Subprovider { private _nonceCache: { [address: string]: string } = {}; private static _reconstructTransaction(payload: JSONRPCPayload): EthereumTx { const raw = payload.params[0]; if (_.isUndefined(raw)) { - throw new Error('Invalid transaction: empty parameters'); + throw new Error(NonceSubproviderErrors.EmptyParametersFound); } const rawData = ethUtil.toBuffer(raw); - return new EthereumTx(rawData); + const transaction = new EthereumTx(rawData); + return transaction; } private static _determineAddress(payload: JSONRPCPayload): string { + let address: string; switch (payload.method) { case 'eth_getTransactionCount': - return payload.params[0].toLowerCase(); + address = payload.params[0].toLowerCase(); + return address; case 'eth_sendRawTransaction': const transaction = NonceTrackerSubprovider._reconstructTransaction(payload); - return `0x${transaction.getSenderAddress().toString('hex')}`.toLowerCase(); + address = `0x${transaction.getSenderAddress().toString('hex')}`.toLowerCase(); + return address; default: - throw new Error(`Invalid Method: ${payload.method}`); + throw new Error(NonceSubproviderErrors.CannotDetermineAddressFromPayload); } } + // Required to implement this public interface which doesn't conform to our linting rule. // tslint:disable-next-line:async-suffix public async handleRequest(payload: JSONRPCPayload, next: OptionalNextCallback, end: ErrorCallback): Promise { switch (payload.method) { case 'eth_getTransactionCount': - const blockTag = providerEngineUtils.blockTagForPayload(payload); - if (!_.isNull(blockTag) && blockTag === 'pending') { + const requestDefaultBlock = providerEngineUtils.blockTagForPayload(payload); + if (requestDefaultBlock === BlockParamLiteral.Pending) { const address = NonceTrackerSubprovider._determineAddress(payload); const cachedResult = this._nonceCache[address]; if (!_.isUndefined(cachedResult)) { @@ -56,11 +63,11 @@ export class NonceTrackerSubprovider extends Subprovider { return next(); } case 'eth_sendRawTransaction': - return next(async (sendTransactionError: Error | null, txResult: any, cb: any) => { + return next((sendTransactionError: Error | null, txResult: any, cb: any) => { if (_.isNull(sendTransactionError)) { this._handleSuccessfulTransaction(payload); } else { - await this._handleSendTransactionErrorAsync(payload, sendTransactionError); + this._handleSendTransactionError(payload, sendTransactionError); } cb(); }); @@ -81,25 +88,10 @@ export class NonceTrackerSubprovider extends Subprovider { nextHexNonce = `0x${nextHexNonce}`; this._nonceCache[address] = nextHexNonce; } - private async _handleSendTransactionErrorAsync(payload: JSONRPCPayload, err: Error): Promise { + private _handleSendTransactionError(payload: JSONRPCPayload, err: Error): void { const address = NonceTrackerSubprovider._determineAddress(payload); - if (this._nonceCache[address]) { - if (_.includes(err.message, NONCE_TOO_LOW_ERROR_MESSAGE)) { - await this._handleNonceTooLowErrorAsync(address); - } - } - } - private async _handleNonceTooLowErrorAsync(address: string): Promise { - const oldNonceInt = ethUtil.bufferToInt(new Buffer(this._nonceCache[address], 'hex')); - delete this._nonceCache[address]; - const nonceResult = await this.emitPayloadAsync({ - method: 'eth_getTransactionCount', - params: [address, 'pending'], - }); - const nonce = nonceResult.result; - const latestNonceInt = ethUtil.bufferToInt(new Buffer(nonce, 'hex')); - if (latestNonceInt > oldNonceInt) { - this._nonceCache[address] = nonce; + if (this._nonceCache[address] && _.includes(err.message, NONCE_TOO_LOW_ERROR_MESSAGE)) { + delete this._nonceCache[address]; } } } diff --git a/packages/subproviders/src/subproviders/redundant_rpc.ts b/packages/subproviders/src/subproviders/redundant_rpc.ts index a3cb463a8..5a94f93d7 100644 --- a/packages/subproviders/src/subproviders/redundant_rpc.ts +++ b/packages/subproviders/src/subproviders/redundant_rpc.ts @@ -35,6 +35,7 @@ export class RedundantRPCSubprovider extends Subprovider { }); }); } + // Required to implement this public interface which doesn't conform to our linting rule. // tslint:disable-next-line:async-suffix public async handleRequest( payload: JSONRPCPayload, diff --git a/packages/subproviders/src/types.ts b/packages/subproviders/src/types.ts index 3db8be943..86b118767 100644 --- a/packages/subproviders/src/types.ts +++ b/packages/subproviders/src/types.ts @@ -112,3 +112,16 @@ export enum LedgerSubproviderErrors { SenderInvalidOrNotSupplied = 'SENDER_INVALID_OR_NOT_SUPPLIED', MultipleOpenConnectionsDisallowed = 'MULTIPLE_OPEN_CONNECTIONS_DISALLOWED', } + +export enum NonceSubproviderErrors { + EmptyParametersFound = 'EMPTY_PARAMETERS_FOUND', + CannotDetermineAddressFromPayload = 'CANNOT_DETERMINE_ADDRESS_FROM_PAYLOAD', +} + +// Re-defined BlockParamLiteral here, rather than import it from 0x.js. +export enum BlockParamLiteral { + Pending = 'pending', +} + +export type OptionalNextCallback = (callback?: (err: Error | null, result: any, cb: any) => void) => void; +export type ErrorCallback = (err: Error | null, data?: any) => void; -- cgit From 4e284f5e6cbe48b307f3d3163dd7f158c56a5e82 Mon Sep 17 00:00:00 2001 From: Jacob Evans Date: Mon, 5 Feb 2018 16:31:51 -0800 Subject: Refactor tests for reuse of the fixture subprovider --- .../test/unit/nonce_tracker_subprovider_test.ts | 156 +++++++-------------- packages/testnet-faucets/Dockerfile | 3 + packages/testnet-faucets/src/ts/global.d.ts | 9 +- 3 files changed, 61 insertions(+), 107 deletions(-) diff --git a/packages/subproviders/test/unit/nonce_tracker_subprovider_test.ts b/packages/subproviders/test/unit/nonce_tracker_subprovider_test.ts index 9bb8268cb..cffb4cdee 100644 --- a/packages/subproviders/test/unit/nonce_tracker_subprovider_test.ts +++ b/packages/subproviders/test/unit/nonce_tracker_subprovider_test.ts @@ -14,86 +14,79 @@ chaiSetup.configure(); describe('NonceTrackerSubprovider', () => { let provider: Web3ProviderEngine; + const getTransactionCountPayload = { + jsonrpc: '2.0', + method: 'eth_getTransactionCount', + params: ['0x0', 'pending'], + id: 1, + }; + const sendTransactionPayload = { + jsonrpc: '2.0', + method: 'eth_sendRawTransaction', + params: [], + id: 1, + }; + const txParams = [ + '0x', + '0x09184e72a000', + '0x2710', + '0x0000000000000000000000000000000000000000', + '0x', + '0x7f7465737432000000000000000000000000000000000000000000000000000000600057', + '0x1c', + '0x5e1d3a76fbf824220eafc8c79ad578ad2b67d01b0c2425eb1f1347e8f50882ab', + '0x5bd428537f05f9830e93792f90ea6a3e2d1ee84952dd96edbae9f658f831ab13', + ]; + function createFixtureSubprovider() { + let called = false; + const fixedBlockNumberAndTransactionCountProvider = new FixtureSubprovider({ + eth_getBlockByNumber: '0x01', + eth_getTransactionCount: (data: any, next: any, end: any) => { + if (called) { + return end(null, '0x99'); + } else { + called = true; + end(null, '0x00'); + } + }, + }); + return fixedBlockNumberAndTransactionCountProvider; + } it('successfully caches the transaction count', async () => { provider = new Web3ProviderEngine(); - let called = false; const nonceTrackerSubprovider = new NonceTrackerSubprovider(); provider.addProvider(nonceTrackerSubprovider); - provider.addProvider( - new FixtureSubprovider({ - eth_getBlockByNumber: '0x01', - eth_getTransactionCount: (data: any, next: any, end: any) => { - if (called) { - return end(null, '0x99'); - } else { - called = true; - end(null, '0x01'); - } - }, - }), - ); + provider.addProvider(createFixtureSubprovider()); provider.start(); - const payload = { - jsonrpc: '2.0', - method: 'eth_getTransactionCount', - params: ['0x0', 'pending'], - id: 1, - }; + const payload = { ...getTransactionCountPayload, params: ['0x0', 'pending'] }; const response = await promisify(provider.sendAsync, provider)(payload); - expect(response.result).to.be.eq('0x01'); + expect(response.result).to.be.eq('0x00'); const secondResponse = await promisify(provider.sendAsync, provider)(payload); - expect(secondResponse.result).to.be.eq('0x01'); + expect(secondResponse.result).to.be.eq('0x00'); }); it('does not cache the result for latest transaction count', async () => { provider = new Web3ProviderEngine(); - let called = false; const nonceTrackerSubprovider = new NonceTrackerSubprovider(); provider.addProvider(nonceTrackerSubprovider); - provider.addProvider( - new FixtureSubprovider({ - eth_getBlockByNumber: '0x01', - eth_getTransactionCount: (data: any, next: any, end: any) => { - if (called) { - return end(null, '0x99'); - } else { - called = true; - end(null, '0x01'); - } - }, - }), - ); + provider.addProvider(createFixtureSubprovider()); provider.start(); - const payload = { - jsonrpc: '2.0', - method: 'eth_getTransactionCount', - params: ['0x0', 'latest'], - id: 1, - }; + const payload = { ...getTransactionCountPayload, params: ['0x0', 'latest'] }; const response = await promisify(provider.sendAsync, provider)(payload); - expect(response.result).to.be.eq('0x01'); + expect(response.result).to.be.eq('0x00'); const secondResponse = await promisify(provider.sendAsync, provider)(payload); expect(secondResponse.result).to.be.eq('0x99'); }); it('clears the cache on a Nonce Too Low Error', async () => { provider = new Web3ProviderEngine(); - let called = false; const nonceTrackerSubprovider = new NonceTrackerSubprovider(); provider.addProvider(nonceTrackerSubprovider); + provider.addProvider(createFixtureSubprovider()); provider.addProvider( new FixtureSubprovider({ - eth_getBlockByNumber: '0x01', - eth_getTransactionCount: (data: any, next: any, end: any) => { - if (called) { - return end(null, '0x99'); - } else { - called = true; - end(null, '0x01'); - } - }, eth_sendRawTransaction: (data: any, next: any, end: any) => { end(new Error('Transaction nonce is too low')); }, @@ -102,35 +95,19 @@ describe('NonceTrackerSubprovider', () => { provider.start(); const noncePayload = { - jsonrpc: '2.0', - method: 'eth_getTransactionCount', + ...getTransactionCountPayload, params: ['0x1f36f546477cda21bf2296c50976f2740247906f', 'pending'], - id: 1, }; - const txParams = [ - '0x', - '0x09184e72a000', - '0x2710', - '0x0000000000000000000000000000000000000000', - '0x', - '0x7f7465737432000000000000000000000000000000000000000000000000000000600057', - '0x1c', - '0x5e1d3a76fbf824220eafc8c79ad578ad2b67d01b0c2425eb1f1347e8f50882ab', - '0x5bd428537f05f9830e93792f90ea6a3e2d1ee84952dd96edbae9f658f831ab13', - ]; - const transaction = new EthereumTx(txParams); const txPayload = { - jsonrpc: '2.0', - method: 'eth_sendRawTransaction', + ...sendTransactionPayload, params: [transaction.serialize()], - id: 1, }; const response = await promisify(provider.sendAsync, provider)(noncePayload); - expect(response.result).to.be.eq('0x01'); + expect(response.result).to.be.eq('0x00'); const secondResponse = await promisify(provider.sendAsync, provider)(noncePayload); - expect(secondResponse.result).to.be.eq('0x01'); + expect(secondResponse.result).to.be.eq('0x00'); try { await promisify(provider.sendAsync, provider)(txPayload); } catch (err) { @@ -138,22 +115,13 @@ describe('NonceTrackerSubprovider', () => { expect(thirdResponse.result).to.be.eq('0x99'); } }); - it('increments the used nonce', async () => { + it('increments the used nonce when a transaction successfully submits', async () => { provider = new Web3ProviderEngine(); - let called = false; const nonceTrackerSubprovider = new NonceTrackerSubprovider(); provider.addProvider(nonceTrackerSubprovider); + provider.addProvider(createFixtureSubprovider()); provider.addProvider( new FixtureSubprovider({ - eth_getBlockByNumber: '0x01', - eth_getTransactionCount: (data: any, next: any, end: any) => { - if (called) { - return end(null, '0x99'); - } else { - called = true; - end(null, '0x00'); - } - }, eth_sendRawTransaction: (data: any, next: any, end: any) => { end(null); }, @@ -162,29 +130,13 @@ describe('NonceTrackerSubprovider', () => { provider.start(); const noncePayload = { - jsonrpc: '2.0', - method: 'eth_getTransactionCount', + ...getTransactionCountPayload, params: ['0x1f36f546477cda21bf2296c50976f2740247906f', 'pending'], - id: 1, }; - const txParams = [ - '0x', - '0x09184e72a000', - '0x2710', - '0x0000000000000000000000000000000000000000', - '0x', - '0x7f7465737432000000000000000000000000000000000000000000000000000000600057', - '0x1c', - '0x5e1d3a76fbf824220eafc8c79ad578ad2b67d01b0c2425eb1f1347e8f50882ab', - '0x5bd428537f05f9830e93792f90ea6a3e2d1ee84952dd96edbae9f658f831ab13', - ]; - const transaction = new EthereumTx(txParams); const txPayload = { - jsonrpc: '2.0', - method: 'eth_sendRawTransaction', + ...sendTransactionPayload, params: [transaction.serialize()], - id: 1, }; const response = await promisify(provider.sendAsync, provider)(noncePayload); diff --git a/packages/testnet-faucets/Dockerfile b/packages/testnet-faucets/Dockerfile index 346f461d8..bd1dcc4a4 100644 --- a/packages/testnet-faucets/Dockerfile +++ b/packages/testnet-faucets/Dockerfile @@ -2,7 +2,10 @@ FROM node WORKDIR /src +# Ledger Provider (in the Subproviders package) requires node-hid at dependency install time +# which compiles and expects certain USB developer library packages to be present RUN apt-get -qq update && apt-get install -y libhidapi-dev libusb-1.0-0-dev +# Our fork of ledgerco disables requiring node-hid at run time if CIRCLECI is set to true ENV CIRCLECI=true COPY package.json . RUN npm i diff --git a/packages/testnet-faucets/src/ts/global.d.ts b/packages/testnet-faucets/src/ts/global.d.ts index b9188bbf6..3d9998698 100644 --- a/packages/testnet-faucets/src/ts/global.d.ts +++ b/packages/testnet-faucets/src/ts/global.d.ts @@ -1,4 +1,7 @@ declare module 'rollbar'; +declare module 'web3-provider-engine/subproviders/rpc'; +declare module 'web3-provider-engine/subproviders/nonce-tracker'; +declare module 'web3-provider-engine/subproviders/hooked-wallet'; declare module '*.json' { const json: any; @@ -33,8 +36,4 @@ declare module 'web3-provider-engine' { } export = Web3ProviderEngine; } -/* tslint:enable */ - -declare module 'web3-provider-engine/subproviders/rpc'; -declare module 'web3-provider-engine/subproviders/nonce-tracker'; -declare module 'web3-provider-engine/subproviders/hooked-wallet'; +/* tslint:enable */ \ No newline at end of file -- cgit From c4680a97a812a50ae5d95c7d2fe2777d704ea0d1 Mon Sep 17 00:00:00 2001 From: Jacob Evans Date: Mon, 5 Feb 2018 16:42:18 -0800 Subject: Yarn.lock --- yarn.lock | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/yarn.lock b/yarn.lock index 7b9ea57c4..c0a67e9d8 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2,6 +2,15 @@ # yarn lockfile v1 +"@0xproject/utils@^0.2.0": + version "0.2.4" + resolved "https://registry.yarnpkg.com/@0xproject/utils/-/utils-0.2.4.tgz#d84d0737f47730e5724a76797d30e716b587a0cf" + dependencies: + bignumber.js "~4.1.0" + js-sha3 "^0.7.0" + lodash "^4.17.4" + web3 "^0.20.0" + "@types/accounting@^0.4.1": version "0.4.1" resolved "https://registry.yarnpkg.com/@types/accounting/-/accounting-0.4.1.tgz#865d9f5694fd7c438fba34eb4bc82eec6f34cdd5" -- cgit From fce70812150340a039a4bc02861e93574c1e965f Mon Sep 17 00:00:00 2001 From: Jacob Evans Date: Mon, 5 Feb 2018 16:57:27 -0800 Subject: Newline prettier/lint --- packages/testnet-faucets/src/ts/global.d.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/testnet-faucets/src/ts/global.d.ts b/packages/testnet-faucets/src/ts/global.d.ts index 3d9998698..41a2f3a8a 100644 --- a/packages/testnet-faucets/src/ts/global.d.ts +++ b/packages/testnet-faucets/src/ts/global.d.ts @@ -36,4 +36,4 @@ declare module 'web3-provider-engine' { } export = Web3ProviderEngine; } -/* tslint:enable */ \ No newline at end of file +/* tslint:enable */ -- cgit From 20590b7d35208bf3fb79ce6f06198ea995b05f91 Mon Sep 17 00:00:00 2001 From: Jacob Evans Date: Mon, 5 Feb 2018 17:11:45 -0800 Subject: Rename called to something more readable --- .../subproviders/test/unit/nonce_tracker_subprovider_test.ts | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/packages/subproviders/test/unit/nonce_tracker_subprovider_test.ts b/packages/subproviders/test/unit/nonce_tracker_subprovider_test.ts index cffb4cdee..738b8bc95 100644 --- a/packages/subproviders/test/unit/nonce_tracker_subprovider_test.ts +++ b/packages/subproviders/test/unit/nonce_tracker_subprovider_test.ts @@ -38,15 +38,16 @@ describe('NonceTrackerSubprovider', () => { '0x5bd428537f05f9830e93792f90ea6a3e2d1ee84952dd96edbae9f658f831ab13', ]; function createFixtureSubprovider() { - let called = false; + let firstGetTransactionCount = true; const fixedBlockNumberAndTransactionCountProvider = new FixtureSubprovider({ eth_getBlockByNumber: '0x01', eth_getTransactionCount: (data: any, next: any, end: any) => { - if (called) { - return end(null, '0x99'); - } else { - called = true; + // For testing caching we return different results on the second call + if (firstGetTransactionCount) { + firstGetTransactionCount = false; end(null, '0x00'); + } else { + end(null, '0x99'); } }, }); -- cgit From 67d7540907b6467c4cdc6a23815ad152517b3328 Mon Sep 17 00:00:00 2001 From: Jacob Evans Date: Tue, 6 Feb 2018 11:27:01 -0800 Subject: Move BlockParam and BlockParamLiteral to shared types --- packages/0x.js/src/index.ts | 4 +--- packages/0x.js/src/types.ts | 14 +++----------- packages/subproviders/package.json | 1 + packages/subproviders/src/index.ts | 2 +- packages/subproviders/src/subproviders/nonce_tracker.ts | 4 +++- packages/subproviders/src/types.ts | 5 ----- packages/types/src/index.ts | 10 ++++++++++ 7 files changed, 19 insertions(+), 21 deletions(-) diff --git a/packages/0x.js/src/index.ts b/packages/0x.js/src/index.ts index 41e67e177..1e12ab4b8 100644 --- a/packages/0x.js/src/index.ts +++ b/packages/0x.js/src/index.ts @@ -2,7 +2,6 @@ export { ZeroEx } from './0x'; export { Order, - BlockParamLiteral, SignedOrder, ECSignature, ZeroExError, @@ -14,7 +13,6 @@ export { TokenEvents, IndexedFilterValues, BlockRange, - BlockParam, OrderCancellationRequest, OrderFillRequest, LogErrorContractEventArgs, @@ -44,6 +42,6 @@ export { OrderState, } from './types'; -export { ContractEventArg, LogWithDecodedArgs, TransactionReceiptWithDecodedLogs } from '@0xproject/types'; +export { BlockParamLiteral, BlockParam, ContractEventArg, LogWithDecodedArgs, TransactionReceiptWithDecodedLogs } from '@0xproject/types'; export { TransactionReceipt } from '@0xproject/types'; diff --git a/packages/0x.js/src/types.ts b/packages/0x.js/src/types.ts index a0deb91c9..a2d1b9eb4 100644 --- a/packages/0x.js/src/types.ts +++ b/packages/0x.js/src/types.ts @@ -1,5 +1,7 @@ -import { ContractEventArg, LogWithDecodedArgs } from '@0xproject/types'; import { BigNumber } from '@0xproject/utils'; + +import { BlockParam, BlockParamLiteral, ContractEventArg, LogWithDecodedArgs } from '@0xproject/types'; + import * as Web3 from 'web3'; export enum ZeroExError { @@ -219,16 +221,6 @@ export interface IndexedFilterValues { [index: string]: ContractEventArg; } -// Earliest is omitted by design. It is simply an alias for the `0` constant and -// is thus not very helpful. Moreover, this type is used in places that only accept -// `latest` or `pending`. -export enum BlockParamLiteral { - Latest = 'latest', - Pending = 'pending', -} - -export type BlockParam = BlockParamLiteral | number; - export interface BlockRange { fromBlock: BlockParam; toBlock: BlockParam; diff --git a/packages/subproviders/package.json b/packages/subproviders/package.json index 4310f8d4a..7934ecb66 100644 --- a/packages/subproviders/package.json +++ b/packages/subproviders/package.json @@ -33,6 +33,7 @@ }, "devDependencies": { "@0xproject/tslint-config": "^0.4.7", + "@0xproject/types": "^0.1.9", "@0xproject/utils": "^0.3.0", "@types/lodash": "^4.14.86", "@types/mocha": "^2.2.42", diff --git a/packages/subproviders/src/index.ts b/packages/subproviders/src/index.ts index 4b3be4efd..67d52ee25 100644 --- a/packages/subproviders/src/index.ts +++ b/packages/subproviders/src/index.ts @@ -10,7 +10,7 @@ export { InjectedWeb3Subprovider } from './subproviders/injected_web3'; export { RedundantRPCSubprovider } from './subproviders/redundant_rpc'; export { LedgerSubprovider } from './subproviders/ledger'; export { NonceTrackerSubprovider } from './subproviders/nonce_tracker'; -export { ECSignature, LedgerWalletSubprovider, LedgerCommunicationClient } from './types'; +export { ECSignature, LedgerWalletSubprovider, LedgerCommunicationClient, NonceSubproviderErrors } from './types'; /** * A factory method for creating a LedgerEthereumClient usable in a browser context. diff --git a/packages/subproviders/src/subproviders/nonce_tracker.ts b/packages/subproviders/src/subproviders/nonce_tracker.ts index 2f94ea581..4b5c34f69 100644 --- a/packages/subproviders/src/subproviders/nonce_tracker.ts +++ b/packages/subproviders/src/subproviders/nonce_tracker.ts @@ -4,14 +4,16 @@ import EthereumTx = require('ethereumjs-tx'); import ethUtil = require('ethereumjs-util'); import providerEngineUtils = require('web3-provider-engine/util/rpc-cache-utils'); +import { BlockParamLiteral } from '@0xproject/types'; + import { - BlockParamLiteral, ErrorCallback, JSONRPCPayload, NonceSubproviderErrors, OptionalNextCallback, } from '../types'; + import { Subprovider } from './subprovider'; const NONCE_TOO_LOW_ERROR_MESSAGE = 'Transaction nonce is too low'; diff --git a/packages/subproviders/src/types.ts b/packages/subproviders/src/types.ts index 86b118767..65b7f6c8f 100644 --- a/packages/subproviders/src/types.ts +++ b/packages/subproviders/src/types.ts @@ -118,10 +118,5 @@ export enum NonceSubproviderErrors { CannotDetermineAddressFromPayload = 'CANNOT_DETERMINE_ADDRESS_FROM_PAYLOAD', } -// Re-defined BlockParamLiteral here, rather than import it from 0x.js. -export enum BlockParamLiteral { - Pending = 'pending', -} - export type OptionalNextCallback = (callback?: (err: Error | null, result: any, cb: any) => void) => void; export type ErrorCallback = (err: Error | null, data?: any) => void; diff --git a/packages/types/src/index.ts b/packages/types/src/index.ts index 7b53b52c4..cb17936f7 100644 --- a/packages/types/src/index.ts +++ b/packages/types/src/index.ts @@ -56,3 +56,13 @@ export enum SolidityTypes { export interface TransactionReceiptWithDecodedLogs extends TransactionReceipt { logs: Array | Web3.LogEntry>; } + +// Earliest is omitted by design. It is simply an alias for the `0` constant and +// is thus not very helpful. Moreover, this type is used in places that only accept +// `latest` or `pending`. +export enum BlockParamLiteral { + Latest = 'latest', + Pending = 'pending', +} + +export type BlockParam = BlockParamLiteral | number; -- cgit From df8de7ff517ba1386671c658d402fa7436ff4f74 Mon Sep 17 00:00:00 2001 From: Jacob Evans Date: Tue, 6 Feb 2018 11:28:40 -0800 Subject: Fixes Rename to isFirstGetTransactionCount assign nextPrefixedHexNonce as a const --- packages/subproviders/src/subproviders/nonce_tracker.ts | 9 +++++---- .../subproviders/test/unit/nonce_tracker_subprovider_test.ts | 6 +++--- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/packages/subproviders/src/subproviders/nonce_tracker.ts b/packages/subproviders/src/subproviders/nonce_tracker.ts index 4b5c34f69..6c1d54882 100644 --- a/packages/subproviders/src/subproviders/nonce_tracker.ts +++ b/packages/subproviders/src/subproviders/nonce_tracker.ts @@ -13,9 +13,9 @@ import { OptionalNextCallback, } from '../types'; - import { Subprovider } from './subprovider'; +// We do not export this since this is not our error, and we do not throw this error const NONCE_TOO_LOW_ERROR_MESSAGE = 'Transaction nonce is too low'; export class NonceTrackerSubprovider extends Subprovider { private _nonceCache: { [address: string]: string } = {}; @@ -36,7 +36,8 @@ export class NonceTrackerSubprovider extends Subprovider { return address; case 'eth_sendRawTransaction': const transaction = NonceTrackerSubprovider._reconstructTransaction(payload); - address = `0x${transaction.getSenderAddress().toString('hex')}`.toLowerCase(); + const addressRaw = transaction.getSenderAddress().toString('hex').toLowerCase(); + address = `0x${addressRaw}`; return address; default: throw new Error(NonceSubproviderErrors.CannotDetermineAddressFromPayload); @@ -87,8 +88,8 @@ export class NonceTrackerSubprovider extends Subprovider { if (nextHexNonce.length % 2) { nextHexNonce = `0${nextHexNonce}`; } - nextHexNonce = `0x${nextHexNonce}`; - this._nonceCache[address] = nextHexNonce; + const nextPrefixedHexNonce = `0x${nextHexNonce}`; + this._nonceCache[address] = nextPrefixedHexNonce; } private _handleSendTransactionError(payload: JSONRPCPayload, err: Error): void { const address = NonceTrackerSubprovider._determineAddress(payload); diff --git a/packages/subproviders/test/unit/nonce_tracker_subprovider_test.ts b/packages/subproviders/test/unit/nonce_tracker_subprovider_test.ts index 738b8bc95..e98d9023c 100644 --- a/packages/subproviders/test/unit/nonce_tracker_subprovider_test.ts +++ b/packages/subproviders/test/unit/nonce_tracker_subprovider_test.ts @@ -38,13 +38,13 @@ describe('NonceTrackerSubprovider', () => { '0x5bd428537f05f9830e93792f90ea6a3e2d1ee84952dd96edbae9f658f831ab13', ]; function createFixtureSubprovider() { - let firstGetTransactionCount = true; + let isFirstGetTransactionCount = true; const fixedBlockNumberAndTransactionCountProvider = new FixtureSubprovider({ eth_getBlockByNumber: '0x01', eth_getTransactionCount: (data: any, next: any, end: any) => { // For testing caching we return different results on the second call - if (firstGetTransactionCount) { - firstGetTransactionCount = false; + if (isFirstGetTransactionCount) { + isFirstGetTransactionCount = false; end(null, '0x00'); } else { end(null, '0x99'); -- cgit From e17ace397cd5d0f4b24d3af868eef8ae55889456 Mon Sep 17 00:00:00 2001 From: Jacob Evans Date: Tue, 6 Feb 2018 11:59:47 -0800 Subject: Move BlockParamLiteral to shared types package Also BlockParam --- packages/0x.js/src/contract_wrappers/contract_wrapper.ts | 3 +-- packages/0x.js/src/contract_wrappers/exchange_wrapper.ts | 3 +-- packages/0x.js/src/index.ts | 8 +++++++- packages/0x.js/src/order_watcher/event_watcher.ts | 4 +++- packages/0x.js/src/order_watcher/order_state_watcher.ts | 3 +-- .../0x.js/src/stores/balance_proxy_allowance_lazy_store.ts | 2 +- .../0x.js/src/stores/order_filled_cancelled_lazy_store.ts | 2 +- packages/0x.js/src/utils/exchange_transfer_simulator.ts | 3 ++- packages/0x.js/test/exchange_transfer_simulator_test.ts | 3 ++- packages/0x.js/test/exchange_wrapper_test.ts | 3 ++- packages/0x.js/test/order_validation_test.ts | 3 ++- packages/subproviders/src/subproviders/nonce_tracker.ts | 12 +++++------- 12 files changed, 28 insertions(+), 21 deletions(-) diff --git a/packages/0x.js/src/contract_wrappers/contract_wrapper.ts b/packages/0x.js/src/contract_wrappers/contract_wrapper.ts index d913e8d9b..b313273b5 100644 --- a/packages/0x.js/src/contract_wrappers/contract_wrapper.ts +++ b/packages/0x.js/src/contract_wrappers/contract_wrapper.ts @@ -1,4 +1,4 @@ -import { LogWithDecodedArgs, RawLog } from '@0xproject/types'; +import { BlockParamLiteral, LogWithDecodedArgs, RawLog } from '@0xproject/types'; import { AbiDecoder, intervalUtils } from '@0xproject/utils'; import { Web3Wrapper } from '@0xproject/web3-wrapper'; import { Block, BlockAndLogStreamer } from 'ethereumjs-blockstream'; @@ -7,7 +7,6 @@ import * as Web3 from 'web3'; import { Artifact, - BlockParamLiteral, BlockRange, ContractEventArgs, ContractEvents, diff --git a/packages/0x.js/src/contract_wrappers/exchange_wrapper.ts b/packages/0x.js/src/contract_wrappers/exchange_wrapper.ts index 63c0d073a..e0c85505c 100644 --- a/packages/0x.js/src/contract_wrappers/exchange_wrapper.ts +++ b/packages/0x.js/src/contract_wrappers/exchange_wrapper.ts @@ -1,5 +1,5 @@ import { schemas } from '@0xproject/json-schemas'; -import { DecodedLogArgs, LogWithDecodedArgs } from '@0xproject/types'; +import { BlockParamLiteral, DecodedLogArgs, LogWithDecodedArgs } from '@0xproject/types'; import { AbiDecoder, BigNumber } from '@0xproject/utils'; import { Web3Wrapper } from '@0xproject/web3-wrapper'; import * as _ from 'lodash'; @@ -7,7 +7,6 @@ import * as Web3 from 'web3'; import { artifacts } from '../artifacts'; import { - BlockParamLiteral, BlockRange, ECSignature, EventCallback, diff --git a/packages/0x.js/src/index.ts b/packages/0x.js/src/index.ts index 1e12ab4b8..c3c8854da 100644 --- a/packages/0x.js/src/index.ts +++ b/packages/0x.js/src/index.ts @@ -42,6 +42,12 @@ export { OrderState, } from './types'; -export { BlockParamLiteral, BlockParam, ContractEventArg, LogWithDecodedArgs, TransactionReceiptWithDecodedLogs } from '@0xproject/types'; +export { + BlockParamLiteral, + BlockParam, + ContractEventArg, + LogWithDecodedArgs, + TransactionReceiptWithDecodedLogs, +} from '@0xproject/types'; export { TransactionReceipt } from '@0xproject/types'; diff --git a/packages/0x.js/src/order_watcher/event_watcher.ts b/packages/0x.js/src/order_watcher/event_watcher.ts index 5d05bfb60..e67b93251 100644 --- a/packages/0x.js/src/order_watcher/event_watcher.ts +++ b/packages/0x.js/src/order_watcher/event_watcher.ts @@ -3,7 +3,9 @@ import { Web3Wrapper } from '@0xproject/web3-wrapper'; import * as _ from 'lodash'; import * as Web3 from 'web3'; -import { BlockParamLiteral, EventWatcherCallback, ZeroExError } from '../types'; +import { BlockParamLiteral } from '@0xproject/types'; + +import { EventWatcherCallback, ZeroExError } from '../types'; import { assert } from '../utils/assert'; const DEFAULT_EVENT_POLLING_INTERVAL_MS = 200; diff --git a/packages/0x.js/src/order_watcher/order_state_watcher.ts b/packages/0x.js/src/order_watcher/order_state_watcher.ts index 1ad1a90b1..a9b3eba68 100644 --- a/packages/0x.js/src/order_watcher/order_state_watcher.ts +++ b/packages/0x.js/src/order_watcher/order_state_watcher.ts @@ -1,5 +1,5 @@ import { schemas } from '@0xproject/json-schemas'; -import { LogWithDecodedArgs } from '@0xproject/types'; +import { BlockParamLiteral, LogWithDecodedArgs } from '@0xproject/types'; import { AbiDecoder, intervalUtils } from '@0xproject/utils'; import { Web3Wrapper } from '@0xproject/web3-wrapper'; import * as _ from 'lodash'; @@ -11,7 +11,6 @@ import { BalanceAndProxyAllowanceLazyStore } from '../stores/balance_proxy_allow import { OrderFilledCancelledLazyStore } from '../stores/order_filled_cancelled_lazy_store'; import { ApprovalContractEventArgs, - BlockParamLiteral, ContractEventArgs, DepositContractEventArgs, EtherTokenEvents, diff --git a/packages/0x.js/src/stores/balance_proxy_allowance_lazy_store.ts b/packages/0x.js/src/stores/balance_proxy_allowance_lazy_store.ts index 33feea105..ede1319fe 100644 --- a/packages/0x.js/src/stores/balance_proxy_allowance_lazy_store.ts +++ b/packages/0x.js/src/stores/balance_proxy_allowance_lazy_store.ts @@ -1,8 +1,8 @@ +import { BlockParamLiteral } from '@0xproject/types'; import { BigNumber } from '@0xproject/utils'; import * as _ from 'lodash'; import { TokenWrapper } from '../contract_wrappers/token_wrapper'; -import { BlockParamLiteral } from '../types'; /** * Copy on read store for balances/proxyAllowances of tokens/accounts diff --git a/packages/0x.js/src/stores/order_filled_cancelled_lazy_store.ts b/packages/0x.js/src/stores/order_filled_cancelled_lazy_store.ts index e22364c09..0a0d93406 100644 --- a/packages/0x.js/src/stores/order_filled_cancelled_lazy_store.ts +++ b/packages/0x.js/src/stores/order_filled_cancelled_lazy_store.ts @@ -1,8 +1,8 @@ +import { BlockParamLiteral } from '@0xproject/types'; import { BigNumber } from '@0xproject/utils'; import * as _ from 'lodash'; import { ExchangeWrapper } from '../contract_wrappers/exchange_wrapper'; -import { BlockParamLiteral } from '../types'; /** * Copy on read store for filled/cancelled taker amounts diff --git a/packages/0x.js/src/utils/exchange_transfer_simulator.ts b/packages/0x.js/src/utils/exchange_transfer_simulator.ts index 662cd210c..9a920c643 100644 --- a/packages/0x.js/src/utils/exchange_transfer_simulator.ts +++ b/packages/0x.js/src/utils/exchange_transfer_simulator.ts @@ -1,9 +1,10 @@ +import { BlockParamLiteral } from '@0xproject/types'; import { BigNumber } from '@0xproject/utils'; import * as _ from 'lodash'; import { TokenWrapper } from '../contract_wrappers/token_wrapper'; import { BalanceAndProxyAllowanceLazyStore } from '../stores/balance_proxy_allowance_lazy_store'; -import { BlockParamLiteral, ExchangeContractErrs, TradeSide, TransferType } from '../types'; +import { ExchangeContractErrs, TradeSide, TransferType } from '../types'; enum FailureReason { Balance = 'balance', diff --git a/packages/0x.js/test/exchange_transfer_simulator_test.ts b/packages/0x.js/test/exchange_transfer_simulator_test.ts index e85a1640f..ba0ee9059 100644 --- a/packages/0x.js/test/exchange_transfer_simulator_test.ts +++ b/packages/0x.js/test/exchange_transfer_simulator_test.ts @@ -1,9 +1,10 @@ import { BlockchainLifecycle, devConstants, web3Factory } from '@0xproject/dev-utils'; +import { BlockParamLiteral } from '@0xproject/types'; import { BigNumber } from '@0xproject/utils'; import * as chai from 'chai'; import { ExchangeContractErrs, Token, ZeroEx } from '../src'; -import { BlockParamLiteral, TradeSide, TransferType } from '../src/types'; +import { TradeSide, TransferType } from '../src/types'; import { ExchangeTransferSimulator } from '../src/utils/exchange_transfer_simulator'; import { chaiSetup } from './utils/chai_setup'; diff --git a/packages/0x.js/test/exchange_wrapper_test.ts b/packages/0x.js/test/exchange_wrapper_test.ts index 044298601..325426438 100644 --- a/packages/0x.js/test/exchange_wrapper_test.ts +++ b/packages/0x.js/test/exchange_wrapper_test.ts @@ -1,4 +1,5 @@ import { BlockchainLifecycle, devConstants, web3Factory } from '@0xproject/dev-utils'; +import { BlockParamLiteral } from '@0xproject/types'; import { BigNumber } from '@0xproject/utils'; import * as chai from 'chai'; import * as _ from 'lodash'; @@ -18,7 +19,7 @@ import { Token, ZeroEx, } from '../src'; -import { BlockParamLiteral, DoneCallback } from '../src/types'; +import { DoneCallback } from '../src/types'; import { chaiSetup } from './utils/chai_setup'; import { constants } from './utils/constants'; diff --git a/packages/0x.js/test/order_validation_test.ts b/packages/0x.js/test/order_validation_test.ts index 934e2e51f..b3dc42396 100644 --- a/packages/0x.js/test/order_validation_test.ts +++ b/packages/0x.js/test/order_validation_test.ts @@ -1,11 +1,12 @@ import { BlockchainLifecycle, devConstants, web3Factory } from '@0xproject/dev-utils'; +import { BlockParamLiteral } from '@0xproject/types'; import { BigNumber } from '@0xproject/utils'; import * as chai from 'chai'; import * as Sinon from 'sinon'; import * as Web3 from 'web3'; import { ExchangeContractErrs, SignedOrder, Token, ZeroEx, ZeroExError } from '../src'; -import { BlockParamLiteral, TradeSide, TransferType } from '../src/types'; +import { TradeSide, TransferType } from '../src/types'; import { ExchangeTransferSimulator } from '../src/utils/exchange_transfer_simulator'; import { OrderValidationUtils } from '../src/utils/order_validation_utils'; diff --git a/packages/subproviders/src/subproviders/nonce_tracker.ts b/packages/subproviders/src/subproviders/nonce_tracker.ts index 6c1d54882..53ee025c9 100644 --- a/packages/subproviders/src/subproviders/nonce_tracker.ts +++ b/packages/subproviders/src/subproviders/nonce_tracker.ts @@ -6,12 +6,7 @@ import providerEngineUtils = require('web3-provider-engine/util/rpc-cache-utils' import { BlockParamLiteral } from '@0xproject/types'; -import { - ErrorCallback, - JSONRPCPayload, - NonceSubproviderErrors, - OptionalNextCallback, -} from '../types'; +import { ErrorCallback, JSONRPCPayload, NonceSubproviderErrors, OptionalNextCallback } from '../types'; import { Subprovider } from './subprovider'; @@ -36,7 +31,10 @@ export class NonceTrackerSubprovider extends Subprovider { return address; case 'eth_sendRawTransaction': const transaction = NonceTrackerSubprovider._reconstructTransaction(payload); - const addressRaw = transaction.getSenderAddress().toString('hex').toLowerCase(); + const addressRaw = transaction + .getSenderAddress() + .toString('hex') + .toLowerCase(); address = `0x${addressRaw}`; return address; default: -- cgit From 4be8eca3fe6a81b468776f5413f25ec726e4e752 Mon Sep 17 00:00:00 2001 From: Jacob Evans Date: Tue, 6 Feb 2018 15:09:03 -0800 Subject: Attribute the origins of NonceTracker NonceTrackerSubprovider is inspired from Web3ProviderEngine NonceTracker --- packages/subproviders/src/subproviders/nonce_tracker.ts | 5 +++++ packages/types/CHANGELOG.md | 2 ++ 2 files changed, 7 insertions(+) diff --git a/packages/subproviders/src/subproviders/nonce_tracker.ts b/packages/subproviders/src/subproviders/nonce_tracker.ts index 53ee025c9..d967d40f2 100644 --- a/packages/subproviders/src/subproviders/nonce_tracker.ts +++ b/packages/subproviders/src/subproviders/nonce_tracker.ts @@ -12,6 +12,11 @@ import { Subprovider } from './subprovider'; // We do not export this since this is not our error, and we do not throw this error const NONCE_TOO_LOW_ERROR_MESSAGE = 'Transaction nonce is too low'; +/* + This class is heavily inspiried by the Web3ProviderEngine NonceSubprovider + We have added the additional feature of clearing any nonce balues when an error message + describes a nonce value being too low. +*/ export class NonceTrackerSubprovider extends Subprovider { private _nonceCache: { [address: string]: string } = {}; private static _reconstructTransaction(payload: JSONRPCPayload): EthereumTx { diff --git a/packages/types/CHANGELOG.md b/packages/types/CHANGELOG.md index 899482c4c..e75d0ddcb 100644 --- a/packages/types/CHANGELOG.md +++ b/packages/types/CHANGELOG.md @@ -1,3 +1,5 @@ # CHANGELOG ## vx.x.x + + * Added BlockLiteralParam and BlockParam, refactored out of 0x.js types. (#355) -- cgit