-
Notifications
You must be signed in to change notification settings - Fork 97
Description
Problem
TransactionPoolService.getPendingCount() is called from two places with fundamentally different availability/correctness requirements:
-
Precheck.sendRawTransactionCheck()— uses the count to compute the expected nonce before submission. If Redis is down, returning0is acceptable: the consensus node will catch any nonce mismatch, and the user gets a meaningful error. -
AccountService.getTransactionCount()(eth_getTransactionCount('pending')) — returns the pending nonce directly to wallets. Returning0here is harmful: the wallet will build a transaction with a stale nonce and enter a confusing retry loop (NONCE_TOO_LOW/ replacement).
Currently the method either always throws (blocking submission entirely) or always returns 0 (giving wallets wrong data). Neither is correct for both callers.
Solution
Add a fallbackToZero flag to getPendingCount(address, fallbackToZero = false).
- When
fallbackToZero = true(used bysendRawTransactionCheck): Redis errors are caught internally, a warning is logged, and0is returned — transactions continue through to consensus which validates the actual nonce. - When
fallbackToZero = false(used bygetTransactionCount, the default): errors propagate as before — the wallet receives an explicit failure rather than a wrong nonce.
async getPendingCount(address: string, fallbackToZero = false): Promise<number> {
if (!TransactionPoolService.isEnabled()) return 0;
try {
return await this.storage.getList(address.toLowerCase());
} catch (error) {
if (fallbackToZero) {
this.logger.warn(error, 'Redis unavailable for getPendingCount, falling back to 0');
return 0;
}
throw error;
}
}Call sites:
// Precheck — graceful degradation, consensus validates nonce
await this.transactionPoolService.getPendingCount(parsedTx.from!, true);
// getTransactionCount — fail fast, wallet must not receive a wrong nonce
await this.transactionPoolService.getPendingCount(address);This keeps error handling centralised inside the service, preserves function purity at the default, and makes the caller's intent explicit without scattering try/catch blocks across the codebase.
Alternatives
No response