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 +++++++++++++++++++++ 3 files changed, 134 insertions(+) create mode 100644 packages/subproviders/src/subproviders/nonce_tracker.ts (limited to 'packages/subproviders/src') 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; + } + } +} -- cgit v1.2.3 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 - packages/subproviders/src/subproviders/nonce_tracker.ts | 11 +++-------- 2 files changed, 3 insertions(+), 9 deletions(-) (limited to 'packages/subproviders/src') 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) => { -- cgit v1.2.3 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(-) (limited to 'packages/subproviders/src') 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 v1.2.3 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/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 +++++ 4 files changed, 40 insertions(+), 32 deletions(-) (limited to 'packages/subproviders/src') 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 v1.2.3 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/subproviders/src/index.ts | 2 +- packages/subproviders/src/subproviders/nonce_tracker.ts | 4 +++- packages/subproviders/src/types.ts | 5 ----- 3 files changed, 4 insertions(+), 7 deletions(-) (limited to 'packages/subproviders/src') 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; -- cgit v1.2.3 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 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'packages/subproviders/src') 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); -- cgit v1.2.3 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/subproviders/src/subproviders/nonce_tracker.ts | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) (limited to 'packages/subproviders/src') 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 v1.2.3 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 +++++ 1 file changed, 5 insertions(+) (limited to 'packages/subproviders/src') 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 { -- cgit v1.2.3