web3-provider-engine
Version:
A JavaScript library for composing Ethereum provider objects using middleware modules
90 lines (77 loc) • 2.61 kB
JavaScript
const inherits = require('util').inherits
const { TransactionFactory } = require('@ethereumjs/tx')
const ethUtil = require('@ethereumjs/util')
const Subprovider = require('./subprovider.js')
const blockTagForPayload = require('../util/rpc-cache-utils').blockTagForPayload
module.exports = NonceTrackerSubprovider
// handles the following RPC methods:
// eth_getTransactionCount (pending only)
//
// observes the following RPC methods:
// eth_sendRawTransaction
// evm_revert (to clear the nonce cache)
inherits(NonceTrackerSubprovider, Subprovider)
function NonceTrackerSubprovider(){
const self = this
self.nonceCache = {}
}
NonceTrackerSubprovider.prototype.handleRequest = function(payload, next, end){
const self = this
switch(payload.method) {
case 'eth_getTransactionCount':
var blockTag = blockTagForPayload(payload)
var address = payload.params[0].toLowerCase()
var cachedResult = self.nonceCache[address]
// only handle requests against the 'pending' blockTag
if (blockTag === 'pending') {
// has a result
if (cachedResult) {
end(null, cachedResult)
// fallthrough then populate cache
} else {
next(function(err, result, cb){
if (err) return cb()
if (self.nonceCache[address] === undefined) {
self.nonceCache[address] = result
}
cb()
})
}
} else {
next()
}
return
case 'eth_sendRawTransaction':
// allow the request to continue normally
next(function(err, result, cb){
// only update local nonce if tx was submitted correctly
if (err) return cb()
// parse raw tx
var rawTx = payload.params[0]
var rawData = Buffer.from(ethUtil.stripHexPrefix(rawTx), 'hex')
const tx = TransactionFactory.fromSerializedData(rawData)
// extract address
var address = tx.getSenderAddress().toString('hex').toLowerCase()
// extract nonce and increment
var nonce = ethUtil.bufferToInt(tx.nonce)
nonce++
// hexify and normalize
var hexNonce = nonce.toString(16)
if (hexNonce.length%2) hexNonce = '0'+hexNonce
hexNonce = '0x'+hexNonce
// dont update our record on the nonce until the submit was successful
// update cache
self.nonceCache[address] = hexNonce
cb()
})
return
// Clear cache on a testrpc revert
case 'evm_revert':
self.nonceCache = {}
next()
return
default:
next()
return
}
}