Skip to content

Commit

Permalink
Add support for pending in getTransactionCount (#3415)
Browse files Browse the repository at this point in the history
* add support for pending in getTxCount

* Add test for pending block arg

* lint
  • Loading branch information
acolytec3 committed May 10, 2024
1 parent 344c173 commit c6aae92
Show file tree
Hide file tree
Showing 2 changed files with 38 additions and 9 deletions.
15 changes: 13 additions & 2 deletions packages/client/src/rpc/modules/eth.ts
Expand Up @@ -770,7 +770,9 @@ export class Eth {
*/
async getTransactionCount(params: [string, string]) {
const [addressHex, blockOpt] = params
const block = await getBlockByOption(blockOpt, this._chain)
let block
if (blockOpt !== 'pending') block = await getBlockByOption(blockOpt, this._chain)
else block = await getBlockByOption('latest', this._chain)

if (this._vm === undefined) {
throw new Error('missing vm')
Expand All @@ -784,7 +786,16 @@ export class Eth {
if (account === undefined) {
return '0x0'
}
return bigIntToHex(account.nonce)

let pendingTxsCount = BIGINT_0

// Add pending txns to nonce if blockOpt is 'pending'
if (blockOpt === 'pending') {
pendingTxsCount = BigInt(
(this.service as FullEthereumService).txPool.pool.get(addressHex.slice(2))?.length ?? 0
)
}
return bigIntToHex(account.nonce + pendingTxsCount)
}

/**
Expand Down
32 changes: 25 additions & 7 deletions packages/client/test/rpc/eth/getTransactionCount.spec.ts
Expand Up @@ -2,11 +2,10 @@ import { Block } from '@ethereumjs/block'
import { Blockchain } from '@ethereumjs/blockchain'
import { Chain, Common, Hardfork } from '@ethereumjs/common'
import { getGenesis } from '@ethereumjs/genesis'
import { LegacyTransaction } from '@ethereumjs/tx'
import { Address } from '@ethereumjs/util'
import { LegacyTransaction, TransactionFactory } from '@ethereumjs/tx'
import { Account, Address, hexToBytes, randomBytes } from '@ethereumjs/util'
import { assert, describe, it } from 'vitest'

import { INVALID_PARAMS } from '../../../src/rpc/error-code.js'
import { createClient, createManager, getRpcClient, startRPC } from '../helpers.js'

import type { FullEthereumService } from '../../../src/service/index.js'
Expand Down Expand Up @@ -74,15 +73,34 @@ describe(method, () => {
assert.equal(res.result, `0x0`, 'should return 0x0 for nonexistent account')
}, 40000)

it('call with unsupported block argument', async () => {
it('call with pending block argument', async () => {
const blockchain = await Blockchain.create()

const client = await createClient({ blockchain, includeVM: true })
const manager = createManager(client)
const service = client.services.find((s) => s.name === 'eth') as FullEthereumService
const rpc = getRpcClient(startRPC(manager.getMethods()))

const res = await rpc.request(method, ['0xccfd725760a68823ff1e062f4cc97e1360e8d997', 'pending'])
assert.equal(res.error.code, INVALID_PARAMS)
assert.ok(res.error.message.includes('"pending" is not yet supported'))
const pk = hexToBytes('0x266682876da8fd86410d001ec33c7c281515aeeb640d175693534062e2599238')
const address = Address.fromPrivateKey(pk)
await service.execution.vm.stateManager.putAccount(address, new Account())
const account = await service.execution.vm.stateManager.getAccount(address)
account!.balance = 0xffffffffffffffn
await service.execution.vm.stateManager.putAccount(address, account!)
const tx = TransactionFactory.fromTxData({
to: randomBytes(20),
value: 1,
maxFeePerGas: 0xffffff,
}).sign(pk)

// Set stubs so getTxCount won't validate txns or mess up state root
service.txPool['validate'] = () => Promise.resolve(undefined)
service.execution.vm.stateManager.setStateRoot = () => Promise.resolve(undefined)
service.execution.vm.shallowCopy = () => Promise.resolve(service.execution.vm)

await service.txPool.add(tx, true)

const res = await rpc.request(method, [address.toString(), 'pending'])
assert.equal(res.result, '0x1')
}, 40000)
})

0 comments on commit c6aae92

Please sign in to comment.