diff --git a/src/chains/ethereum/ethereum/src/api.ts b/src/chains/ethereum/ethereum/src/api.ts index b12dca8cdf..0b9567e9f4 100644 --- a/src/chains/ethereum/ethereum/src/api.ts +++ b/src/chains/ethereum/ethereum/src/api.ts @@ -3437,6 +3437,36 @@ export default class EthereumApi implements Api { }; } + + /** + * Returns the number of transactions created by specified address currently pending for inclusion in the next block(s), as well as the ones that are being scheduled for future execution only. + * + * @param address - The account address + * @returns The count of transactions currently pending or queued in the transaction pool by address. + * @example + * ```javascript + * const [from] = await provider.request({ method: "eth_accounts", params: [] }); + * const pendingTx = await provider.request({ method: "eth_sendTransaction", params: [{ from, gas: "0x5b8d80", nonce:"0x0" }] }); + * const queuedTx = await provider.request({ method: "eth_sendTransaction", params: [{ from, gas: "0x5b8d80", nonce:"0x2" }] }); + * const pool = await provider.send("txpool_contentFrom", [from]); + * console.log(pool); + * ``` + */ + @assertArgLength(1) + async txpool_contentFrom(address: DATA): Promise> { + const { transactions } = this.#blockchain; + const { + transactionPool: { executables, origins, processMap } + } = transactions; + + const fromAddress = Address.from(address); + + return { + pending: processMap(executables.pending, fromAddress), + queued: processMap(origins, fromAddress) + }; + } + /** * Returns the number of transactions currently pending for inclusion in the next block(s), as well as the ones that are being scheduled for future execution only. * diff --git a/src/chains/ethereum/ethereum/src/transaction-pool.ts b/src/chains/ethereum/ethereum/src/transaction-pool.ts index b09847bab0..4f7586ffd0 100644 --- a/src/chains/ethereum/ethereum/src/transaction-pool.ts +++ b/src/chains/ethereum/ethereum/src/transaction-pool.ts @@ -15,6 +15,7 @@ import { EthereumInternalOptions } from "@ganache/ethereum-options"; import { Executables } from "./miner/executables"; import { TypedTransaction } from "@ganache/ethereum-transaction"; import { Ethereum } from "./api-types"; +import { Address } from "@ganache/ethereum-address"; /** * Checks if the `replacer` is eligible to replace the `replacee` transaction @@ -454,7 +455,7 @@ export default class TransactionPool extends Emittery<{ drain: undefined }> { return null; } - public processMap(map: Map>) { + public processMap(map: Map>, address?: Address) { let res: Record< string, Record> @@ -463,6 +464,11 @@ export default class TransactionPool extends Emittery<{ drain: undefined }> { for (let [_, { array, length }] of map) { for (let i = 0; i < length; ++i) { const transaction = array[i]; + + if(address && transaction.from.toString() != address.toString()) { + continue; + } + const from = transaction.from.toString(); if (res[from] === undefined) { res[from] = {}; diff --git a/src/chains/ethereum/ethereum/tests/api/txpool/txpool.test.ts b/src/chains/ethereum/ethereum/tests/api/txpool/txpool.test.ts index c8745f75b0..e23abec1ad 100644 --- a/src/chains/ethereum/ethereum/tests/api/txpool/txpool.test.ts +++ b/src/chains/ethereum/ethereum/tests/api/txpool/txpool.test.ts @@ -121,6 +121,64 @@ describe("txpool", () => { }); }); + describe("contentFrom", () => { + let provider: EthereumProvider; + let accounts: string[]; + + beforeEach(async () => { + provider = await getProvider({ + miner: { blockTime: 1000 } + }); + accounts = await provider.send("eth_accounts"); + }); + + it("handles pending and queued transactions", async () => { + const pendingTransactions = await Promise.all([ + provider.send("eth_sendTransaction", [ + { + from: accounts[1], + to: accounts[2] + } + ]), + provider.send("eth_sendTransaction", [ + { + from: accounts[2], + to: accounts[3] + } + ]), + provider.send("eth_sendTransaction", [ + { + from: accounts[1], + to: accounts[2] + } + ]) + ]); + + const queuedTransactions = await Promise.all([ + provider.send("eth_sendTransaction", [ + { + from: accounts[1], + to: accounts[2], + nonce: "0x123", + } + ]) + ]); + + const { pending, queued } = await provider.send("txpool_contentFrom", [accounts[1]]); + + const pendingAddresses = Object.keys(pending); + const queuedAddresses = Object.keys(queued); + + assert(pendingAddresses.findIndex((value) => value === accounts[1]) == 0) + assert(pendingAddresses.findIndex((value) => value === accounts[2]) == -1) + assert(pendingAddresses.length == 1) + + assert(queuedAddresses.findIndex((value) => value === accounts[1]) == 0) + assert(queuedAddresses.findIndex((value) => value === accounts[2]) == -1) + assert(queuedAddresses.length == 1) + }) + }) + describe("status", () => { let provider: EthereumProvider; let accounts: string[];