import { Block } from '@tevm/block'; import { TypedTransaction, ImpersonatedTx } from '@tevm/tx'; import { EthjsAddress } from '@tevm/utils'; import { Vm } from '@tevm/vm'; interface TxPoolOptions { vm: Vm; maxSize?: number; maxPerSender?: number; } type TxPoolObject = { tx: TypedTransaction | ImpersonatedTx; hash: UnprefixedHash; added: number; error?: Error; }; type UnprefixedAddress = string; type UnprefixedHash = string; /** * @module service */ /** * @experimental * Tx pool (mempool) * @memberof module:service */ declare class TxPool { private vm; private maxSize; private maxPerSender; private opened; running: boolean; private _cleanupInterval; private _logInterval; /** * The central pool dataset. * * Maps an address to a `TxPoolObject` */ pool: Map; /** * Transactions in nonce order for all senders */ txsInNonceOrder: Map; /** * Transactions by hash */ txsByHash: Map; /** * Transactions by account and nonce */ txsByNonce: Map>; /** * The number of txs currently in the pool */ txsInPool: number; /** * Map for handled tx hashes * (have been added to the pool at some point) * * This is meant to be a superset of the tx pool * so at any point it time containing minimally * all txs from the pool. */ private handled; /** * Activate before chain head is reached to start * tx pool preparation (sorting out included txs) */ BLOCKS_BEFORE_TARGET_HEIGHT_ACTIVATION: number; /** * Number of minutes to keep txs in the pool */ POOLED_STORAGE_TIME_LIMIT: number; /** * Number of minutes to forget about handled * txs (for cleanup/memory reasons) */ HANDLED_CLEANUP_TIME_LIMIT: number; /** * Create new tx pool * @param options constructor parameters */ constructor({ vm, maxSize, maxPerSender }: TxPoolOptions); deepCopy(opt: TxPoolOptions): TxPool; /** * Open pool */ open(): boolean; /** * Start tx processing */ start(): boolean; private validateTxGasBump; /** * Validates a transaction against the pool and other constraints * @param tx The tx to validate */ private validate; /** * Adds a tx to the pool without validating it. * * If there is a tx in the pool with the same address and * nonce it will be replaced by the new tx, if it has a sufficient gas bump. * This also verifies certain constraints, if these are not met, tx will not be added to the pool. * @param tx Transaction * @param isLocalTransaction if this is a local transaction (loosens some constraints) (default: false) */ addUnverified(tx: TypedTransaction | ImpersonatedTx): Promise<{ error: null; hash: `0x${string}`; } | { error: string; hash: `0x${string}`; }>; /** * Adds a tx to the pool. * * If there is a tx in the pool with the same address and * nonce it will be replaced by the new tx, if it has a sufficient gas bump. * This also verifies certain constraints, if these are not met, tx will not be added to the pool. * @param tx Transaction * @param isLocalTransaction if this is a local transaction (loosens some constraints) (default: false) */ add(tx: TypedTransaction | ImpersonatedTx, requireSignature?: boolean, skipBalance?: boolean): Promise<{ error: null; hash: `0x${string}`; } | { error: string; hash: `0x${string}`; }>; /** * Returns the available txs from the pool * @param txHashes * @returns Array with tx objects */ getByHash(txHashes: string): TypedTransaction | ImpersonatedTx | null; getByHash(txHashes: ReadonlyArray): Array; /** * Removes the given tx from the pool * @param txHash Hash of the transaction */ removeByHash(txHash: string): void; /** * Remove txs included in the latest blocks from the tx pool */ removeNewBlockTxs(newBlocks: Block[]): void; /** * Regular tx pool cleanup */ cleanup(): void; /** * Helper to return a normalized gas price across different * transaction types. Providing the baseFee param returns the * priority tip, and omitting it returns the max total fee. * @param tx The tx * @param baseFee Provide a baseFee to subtract from the legacy * gasPrice to determine the leftover priority tip. */ private normalizedGasPrice; /** * Returns the GasPrice object to provide information of the tx' gas prices * @param tx Tx to use * @returns Gas price (both tip and max fee) */ private txGasPrice; getBySenderAddress(address: EthjsAddress): Promise>; /** * Get all pending transactions in the pool * @returns Array of transactions */ getPendingTransactions(): Promise>; /** * Get transaction status * @param txHash Transaction hash * @returns Transaction status: 'pending', 'mined', or 'unknown' */ getTransactionStatus(txHash: string): Promise<'pending' | 'mined' | 'unknown'>; /** * Events system for transaction pool */ private events; /** * Register an event handler * @param event Event name ('txadded' or 'txremoved') * @param callback Handler function */ on(event: 'txadded' | 'txremoved', callback: (hash: string) => void): void; /** * Fire an event * @param event Event name * @param hash Transaction hash */ private fireEvent; /** * Handle block being added to the chain * @param block The block that was added */ onBlockAdded(block: Block): Promise; /** * Handle chain reorganization * @param removedBlocks Blocks that were removed from the canonical chain * @param addedBlocks Blocks that were added to the canonical chain */ onChainReorganization(removedBlocks: Block[], addedBlocks: Block[]): Promise; /** * Returns eligible txs to be mined sorted by price in such a way that the * nonce orderings within a single account are maintained. * * Note, this is not as trivial as it seems from the first look as there are three * different criteria that need to be taken into account (price, nonce, account * match), which cannot be done with any plain sorting method, as certain items * cannot be compared without context. * * This method first sorts the separates the list of transactions into individual * sender accounts and sorts them by nonce. After the account nonce ordering is * satisfied, the results are merged back together by price, always comparing only * the head transaction from each account. This is done via a heap to keep it fast. * * @param baseFee Provide a baseFee to exclude txs with a lower gasPrice */ txsByPriceAndNonce({ baseFee, allowedBlobs }?: { baseFee?: bigint; allowedBlobs?: number; }): Promise<(TypedTransaction | ImpersonatedTx)[]>; /** * Stop pool execution */ stop(): boolean; /** * Close pool */ close(): void; /** * Clears the pool of all transactions. */ clear(): Promise; logStats(): void; _logPoolStats(): void; } export { TxPool };