Fix eth_getTransactionReceipt race condition#1802
Fix eth_getTransactionReceipt race condition#1802librelois merged 20 commits intopolkadot-evm:masterfrom
eth_getTransactionReceipt race condition#1802Conversation
ba8c8fd to
5d7e6f0
Compare
5d7e6f0 to
105efa2
Compare
ethers.js v6 caches eth_getTransactionCount responses at the provider level. When multiple tests run sequentially using the same signer, subsequent tests may receive stale cached nonces instead of making fresh RPC calls. This fixes the "nonce has already been used" test failures by: - Using direct RPC calls (context.ethersjs.send) to bypass caching - Explicitly setting nonces in transactions to ensure correctness The backend changes to latest_block_hash() use mapping-sync as the source of truth for consistency with other RPCs. When the best block isn't indexed yet, it falls back to the latest indexed block.
|
@sorpaas we would appreciate to have your feedback on this PR, can you take a look? Thanks |
librelois
left a comment
There was a problem hiding this comment.
Missing Database Migration
The diff adds a new column BLOCK_NUMBER_MAPPING = 4 and changes NUM_COLUMNS from 4 to 5, but upgrade.rs still shows:
CURRENT_VERSION: u32 = 2
V2_NUM_COLUMNS: u32 = 4
Existing databases won't have column 4 populated for already-synced blocks. After an upgrade, historical blocks won't be queryable via eth_getBlockByNumber until re-synced from scratch. A migration from version 2 to version 3 should be added to backfill the block_number -> ethereum_block_hash mapping.
Added KV store migration in 091f2ae |
* test: 🧪 add TDD failing test
* refactor: ♻️ use mapping-sync as single source of truth for eth_ RPCs
* fix: 🐛 fix missing args
* test: ✅ redefine waitForBlock as a polling function
* style: 🎨 fmt
* fix: 🐛 wait for the right block number
* revert: 🔥 remove temporary delay
* chore: 📦 update package lock
* test: ✅ update test timeouts
* test: ✅ remove explicit nonce to fix EIP-7702 test race condition
* fix: bypass ethers.js nonce caching in EIP-7702 tests
ethers.js v6 caches eth_getTransactionCount responses at the provider
level. When multiple tests run sequentially using the same signer,
subsequent tests may receive stale cached nonces instead of making
fresh RPC calls.
This fixes the "nonce has already been used" test failures by:
- Using direct RPC calls (context.ethersjs.send) to bypass caching
- Explicitly setting nonces in transactions to ensure correctness
The backend changes to latest_block_hash() use mapping-sync as the
source of truth for consistency with other RPCs. When the best block
isn't indexed yet, it falls back to the latest indexed block.
* fix: 🐛 verify mapped blocks against canonical chain during reorgs
* revert: 🔥 remove LATEST_INDEXED_BLOCK
* fix: 🐛 correctly error instead of defaulting to block number 0
* fix: 🐛 verify all non-genesis blocks
* test: ✅ add error handling to waitForBlock
* fix: 🐛 use consistent behavior for eth_getBlockByNumber("latest") on SQL backend
* feat: ✨ add KV store migration
* fix: 🐛 do not default to 0
* feat: 🔊 log processed entries in parity db migration
* test: 🧪 add TDD failing test
* refactor: ♻️ use mapping-sync as single source of truth for eth_ RPCs
* fix: 🐛 fix missing args
* test: ✅ redefine waitForBlock as a polling function
* style: 🎨 fmt
* fix: 🐛 wait for the right block number
* revert: 🔥 remove temporary delay
* chore: 📦 update package lock
* test: ✅ update test timeouts
* test: ✅ remove explicit nonce to fix EIP-7702 test race condition
* fix: bypass ethers.js nonce caching in EIP-7702 tests
ethers.js v6 caches eth_getTransactionCount responses at the provider
level. When multiple tests run sequentially using the same signer,
subsequent tests may receive stale cached nonces instead of making
fresh RPC calls.
This fixes the "nonce has already been used" test failures by:
- Using direct RPC calls (context.ethersjs.send) to bypass caching
- Explicitly setting nonces in transactions to ensure correctness
The backend changes to latest_block_hash() use mapping-sync as the
source of truth for consistency with other RPCs. When the best block
isn't indexed yet, it falls back to the latest indexed block.
* fix: 🐛 verify mapped blocks against canonical chain during reorgs
* revert: 🔥 remove LATEST_INDEXED_BLOCK
* fix: 🐛 correctly error instead of defaulting to block number 0
* fix: 🐛 verify all non-genesis blocks
* test: ✅ add error handling to waitForBlock
* fix: 🐛 use consistent behavior for eth_getBlockByNumber("latest") on SQL backend
* feat: ✨ add KV store migration
* fix: 🐛 do not default to 0
* feat: 🔊 log processed entries in parity db migration
Problem
Users report intermittent issues where
eth_getTransactionReceiptreturns null immediately after getting a transaction hash frometh_getBlockByNumber. This happens because:eth_getBlockByNumberreads from runtime storage (available immediately after block import)eth_getTransactionReceiptreads from themapping-syncdatabase (delayed until worker processes the block)Solution
Rely on
mapping-syncstorage for all impacted RPCs.Changes
ts-tests/tests/test-receipt-consistency.ts: Integration tests for receipt consistencyTesting
The TDD commit includes an artificial 2-second delay in
mapping-syncto reliably reproduce the race condition. Remove before merging.