2026 Release v2.9.0 dev upgrade merge - #2557
Open
benjamin202410 wants to merge 173 commits into
Open
benjamin202410 wants to merge 173 commits into
benjamin202410 wants to merge 173 commits into
Conversation
…thereum#18963 ethereum#19131 ethereum#19433 ethereum#19593 ethereum#19661 ethereum#19749 ethereum#19963 (#2346) Introduce p2p/enode as the generalized node representation for peer and discovery code. The new package becomes the home for node records, local nodes, URL parsing, and the node database, while the v4 identity scheme moves out of p2p/enr to decouple ENR handling from Ethereum-specific crypto. Port discovery, peer management, node APIs, and simulations to enode.Node and enode.ID. The discovery wire protocol stays unchanged, but APIs move away from discover.Node and NodeID and now require explicit record validation. Simulation helpers now track complete nodes and the updated tests cover the new connect and network behavior. These changes align the fork with the upstream geth enode refactor and make later p2p and discovery updates easier to carry. Existing simulation snapshots are incompatible with the new node identifier representation.
PR #2329 promoted six XDC fork settings to top-level ChainConfig fields and added validation that rejects an XDPoS genesis missing them. The puppeth wizard was not updated, so generated XDPoS genesis files failed with 'invalid chain config: missing fork switch: TRC21IssuerSMC'. Hardcode the four system contract addresses (TRC21IssuerSMC, XDCXListingSMC, RelayerRegistrationSMC, LendingRegistrationSMC) to their canonical mainnet values, and prompt for TIPTRC21FeeBlock and Gas50xBlock via the wizard. Gas50xBlock input is validated to be greater than or equal to TIPTRC21FeeBlock, with interactive re-entry on invalid values.
Guard BFT broadcast enqueue with the quit channel so Vote/Timeout/SyncInfo exit cleanly once shutdown starts. Add a regression test to ensure Vote returns after BFT loop stop and does not hang.
…19061 (#2368) Co-authored-by: Matthew Halpern <[email protected]>
Replace the fixed sleep and one-shot synchronise call with a timeout-based retry loop so the test tolerates CI scheduling variance. Add protocol manager cleanup to avoid leaking background work between test runs.
…ethereum#19362 (#2369) This resolves a minor issue where neighbors responses containing less than 16 nodes would bump the failure counter, removing the node. One situation where this can happen is a private deployment where the total number of extant nodes is less than 16. Issue found by @Jsying. Co-authored-by: Felix Lange <[email protected]>
…19712 (#2370) Co-authored-by: Felix Lange <[email protected]>
…2371) Co-authored-by: Martin Holst Swende <[email protected]>
This entry was an experiment, but we're moving on to the entry-per-protocol instead. Co-authored-by: Felix Lange <[email protected]>
…m#19799 (#2374) Make it select from all live nodes instead of selecting the heads of random buckets. Co-authored-by: Felix Lange <[email protected]>
Co-authored-by: Felix Lange <[email protected]>
…ereum#20367 (#2382) * p2p/discv5: add deprecation warning and remove unused code * p2p/discv5: remove unused variables Co-authored-by: Felix Lange <[email protected]>
… (#2410) Co-authored-by: ucwong <[email protected]>
Co-authored-by: ucwong <[email protected]>
…um#20846 (#2408) Co-authored-by: ucwong <[email protected]>
) * p2p: wait for goroutine exit, fixes ethereum#20558 * p2p: wait for all slots on exit Co-authored-by: Felix Lange <[email protected]> Co-authored-by: Martin Holst Swende <[email protected]>
…eum#20573 (#2385) This is a temporary fix for a problem which started happening when the dialer was changed to read nodes from an enode.Iterator. Before the iterator change, discovery queries would always return within a couple seconds even if there was no Internet access. Since the iterator won't return unless a node is actually found, discoverTask can take much longer. This means that the 'emergency connect' logic might not execute in time, leading to a stuck node. Co-authored-by: Felix Lange <[email protected]>
Concurrent removePeer callers (BFT broadcast loops, DAO fork timers, normal teardown, and the downloader/fetcher drop callbacks) can all pass the Peer(id) lookup before the first caller unregisters the peer, so each re-runs the unregister sequence and floods the logs with "peer is not registered" warnings on every peer drop. Mark peer removal with an atomic flag so the unregister sequence runs exactly once, and let downloader.UnregisterPeer treat an unregistered peer as a silent no-op. In the same race window, handle() could register a peer in the downloader after its removal was claimed, leaving a stale entry that blocks a reconnect of the same node id; re-check the flag after registering and undo the registration.
… race ethereum#35096 (#2539) Port go-ethereum PR ethereum#35096. Move journal.close() from the loop goroutine's deferred call into Stop(), guarded by tracker.mu, so the journal is deterministically closed after wg.Wait() instead of racing with concurrent Track/TrackAll access during shutdown. The load/setupWriter half was already present in Start() on dev-upgrade.
The sync status logger only fired while the downloader was inside a bulk historical sync. Once the node is caught up, new blocks are followed through the block fetcher / BFT announcements, so Synchronising() stays false and the warn log appeared only once or never over hours of normal operation instead of every 10 minutes. The logger now emits a status line on every 10-minute cycle with a neutral message (current / highest / behind / peers). While the downloader is actively synchronising it seeds current and highest from the downloader's progress (the snap block and the discovered target); otherwise it seeds current from the local chain head. In both states the reported highest is the maximum of the seeded value and the per-peer live high-water mark fed by block announcements (NewBlockMsg / NewBlockHashesMsg), so the gap stays current even when the downloader is idle. The announced numbers are only trusted after passing the fetcher's plausibility window, exposed as IsPlausibleAnnouncement, so a peer cannot inflate the reported gap.
…tion ethereum#28837 (#2542) Sync() could block forever: the resetDone branch notified the sync waiter with a non-blocking send and then unconditionally cleared it. When Sync() had not yet reached its receive (a scheduling gap after it sent its waiter), the notification was dropped, leaving the waiter never signaled. Restore the blocking send used upstream geth, which cannot lose the notification, and do the same for the loop-termination notification so a pool closed while Sync() is pending also signals the waiter. Add TestSyncCompletes which exercises repeated Sync() calls and would hang under -cover if the non-blocking notification regressed.
…bmit (#2537) A local transaction that reaches the pool through a concurrent submission (peer gossip, wallet retry, or a parallel RPC endpoint) returns txpool.ErrAlreadyKnown from TxPool.Add, but is not in the desired local tracking state: the local tracker only starts on a successful admission. If that transaction is later evicted, it has no local resubmit or journal protection and silently disappears. Treat ErrAlreadyKnown as the desired state on the initial admission path: AddLocal and EthAPIBackend.SendTx still surface the error to the caller (matching upstream go-ethereum semantics), but now also register the transaction with the local tracker so it keeps the resubmit and journal guarantees. The resubmit loop (TxTracker.loop -> TxTracker.recheck) already retains already-known transactions in the tracked set, because recheck skips transactions still present in the pool (pool.Has), so the two paths are now consistent.
… error ethereum#35048 (#2543) * fix(core/txpool): subscribe to head events in New to avoid loss ethereum#35048 The pool subscribed to chain head events only after its loop goroutine started, so a head event emitted by InsertChain right after New could be missed. The pool then reset against a stale head, keeping pending nonces at genesis and rejecting fresh transactions as ErrNonceTooHigh (this also caused the TestResubmit/TestJournal flakes). Move the subscription into New so events are captured from the start, and add TestHeadEventDeliveredAfterNew which waits for the pool to observe the head inserted right after New. * fix(core/txpool): release head event subscription on Init error New subscribes to chain head events before the fallible SubPool.Init calls. When Init fails, New returns without starting the loop, so the loop's deferred Unsubscribe never runs and the chain feed stays subscribed to an unconsumed, unbuffered channel; a later head publication can block until the whole blockchain is stopped. Unsubscribe on this error path before returning, and add TestNewUnsubscribesOnInitError which fails if the subscription is leaked.
TestIsYourTurnConsensusV2CrossConfig was flaky in CI: the first YourTurn call could be rounded up to the switched-to config's mine period (round 10 -> 3s) because the check compares against Unix-second granularity, returning true and failing the assert.False. The second check also under-slept since UpdateParams only repoints the engine's CurrentConfig, so MinePeriod read from blockchain.Config() stayed at the pre-switch value (2s). Derive the effective mine period from Config(round 10), wait strictly inside it for the first check, and comfortably past it for the second.
…ier forks (#2532) A gas schedule fork raises the pool's minimum gas price above transactions admitted under the previous tier. No node admits or relays them any more, yet they stay in the pending list and keep pendingNonces past them, so wallets reading the pending nonce keep building on top of a transaction the network has priced out. After a reset, compare the floor of the block pending on the head the pool landed on with the one its previous head implied, and on a rise drop every non-special transaction priced below the new floor from both the pending list and the queue. The queue is swept as well because promoteExecutables does not check price and would otherwise promote those transactions straight back into pending. The price heap is charged once for the whole sweep rather than once per removal, the way SetGasTip charges its own. The scan is boundary triggered, so a reset that does not raise the floor costs two floor lookups and one comparison, and a reorg that lowers the floor never triggers it. Special transactions are exempt exactly as they are during admission, being consensus critical and generated with a zero gas price. A swept transaction does not come back. A reorg below the fork restores the floor but not the pool, so resubmitting the transaction is accepted again only until the chain re-crosses the fork and the next reset prices it out; its sender has to resign at the new price for the transaction to stick.
…2541) * fix(core/txpool/locals): drop the transaction a tracked local tx replaces TrackAll only ever added to the tracked set, while the per-nonce SortedMap silently overwrote the entry a replacement displaced. The replaced transaction was therefore never returned by Forward again, stayed tracked forever, was rewritten into the journal on every rotation and could win the nonce on the next load, resurrecting a transaction the user had already replaced, because rotation writes the tracked set in map order through a non-stable sort. Decide which of the two supersedes the other the way the pool decides it. While the pool holds one of them it is authoritative: it occupies a nonce with at most one transaction, and AddLocal tracks a local transaction only after Add has released the subpool lock, so two concurrent submissions can be accepted in one order and reach TrackAll in the other. When the pool holds neither -- two submissions it has since discarded, or a journal an older version wrote -- fall back to the substitution rules legacypool applies in list.Add: a special transaction always claims its nonce, a regular one must not evict a pending special one, and otherwise a replacement has to beat the transaction it replaces on both fee cap and tip. The price bump is deliberately not repeated here: it is pool policy, and a transaction that beats the old one but misses the bump behaves exactly as before, so no case gets worse. Load now converges a journal written by an older version on the replacement rather than on whichever entry the rotation happened to sort last, so the entry later in the file no longer decides the nonce. That is a behaviour change for journals left behind by an older version: the replacement survives now even when it was written first. Equally priced transactions are not a substitution either, so the one already tracked keeps the nonce where the previous behaviour let the later one take it. Build the test environment from an explicit chain config so tests can pin the gas schedule instead of sharing the package level genesis, and price the shared replacement pair to clear the pool's price bump, which is what makes it a substitution rather than two transactions the pool would reject. Cover both orders in which a replacement can reach the tracker, the concurrent interleaving where the original is added first and tracked last, the fallback for two transactions the pool holds neither of, the special transaction rules in both directions, the tie between equally priced transactions, and a dearer tracked transaction losing to the one the pool accepted. * fix(core/txpool,core/txpool/locals): hold back local resubmits below the gas price floor A gas schedule fork raises the floor above transactions that were admitted under the previous tier, and the pool sweeps them out. The local tracker kept resubmitting them every minute: recheck ignored the result of pool.Add, and the transactions never went stale because their nonce never advanced, so they stayed tracked and journalled forever. Hold back any tracked transaction priced below the current floor, resolved for the block pending on top of the head exactly as admission validation resolves it. They stay tracked, so a reorg or a set-head rollback that lowers the floor picks them up again on the next recheck: the pool does not bring back what it swept, so the tracker is the only thing that can. Special transactions stay exempt, as they are during admission. Resolve the floor through a new TxPool.MinGasPrice, which goes through the same pendingBlockNumber helper as admission validation and the sweep, so the tracker and the pool cannot price the same transaction at different heights. Report the held back transactions through txpool/local/belowfloor, since they are still counted by txpool/local. Pin that ErrUnderMinGasPrice is not a temporary reject: the floor only rises as the chain advances, so retrying cannot help and AddLocal must not track the transaction, but the error must not be used to drop a tracked one either. Cover the floor with tests that rewind the head with SetHead across every tier boundary and cover a head without a block number, the hold-back at exactly the floor and one wei below it, resumption once the floor drops, and the exemption special transactions keep.
…2549) Target 2026-09-08 10:00 CST (02:00 UTC), derived from the devnet stats snapshot: head 1185928 seen at 2026-09-03 19:26:54 CST with a measured 2.0s block time. Keep genesis/devnet.json in sync with DevnetChainConfig so `XDC init --devnet` and `XDC --devnet` schedule the same fork, and drop devnet from the assertion that default XDC networks leave gas2500x unscheduled.
…n head, close #2533 (#2547) Side chain blocks are written by hash without state, so a node whose head sits below them still answers HasBlock for the whole segment; findAncestor then resolved the ancestor above its own head and the sync resumed there, stranding the range in between. On XDPoS this stalls the head for good: epoch-switch header verification needs the gap block's masternode snapshot, which is only written when the gap block imports with state. Cap both searches at the local head. calculateRequestSpan now always asks for two samples spaced one skipped header apart, taking its top sample from the highest block below the remote head and clamping it down to the local head, so the window never spends a round trip on a block the head guard would reject; findAncestor bounds the binary search with the same limit. The window keeps its count when 'from' is clamped up to zero, which can top it out above the head, so usableAsAncestor still rejects those candidates and keeps a span hit from being returned above the head. A hit on the lower sample no longer ends the search: the true fork can sit on the skipped block, so the hit seeds the binary search with the gap under the next sample, clamped by the local head and by the remote height. Covered by blocks-above-head tests in full and fast sync (stubs stored by hash, carrying receipts in fast sync but never entering the canonical chain, so the snap head stays pinned), span candidate rejection and the head-0 and head-2 window clamps, the gap refinement, a remote sitting at genesis, a binary-search fork variant, per-mode head-guard boundaries, the write-without-state semantics the bug rests on, and the per-case request span and window max.
…2545) The exact error string from crypto.Ecrecover differs between the cgo backend (invalid signature length) and the pure-Go nocgo backend (invalid signature) for a malformed signature. Assert on the shared substring to avoid flakiness depending on whether CGO is enabled at build time.
Replace net.Conn.Read with io.ReadFull in TestTCPPipe and TestTCPPipeBidirections. A single TCP Read is not guaranteed to fill the buffer, so on loopback stacks that fragment the 1024-byte writes (e.g. WSL2) the test compared a partial read against the full message and failed at the same byte boundary on every run. TestNetPipe is unaffected because net.Pipe delivers each Write as one Read.
UpdateBlocksHashCache appended unconditionally, so refreshing the cache for a block that was already cached — which the known-block path now does when it promotes a stored block — grew the per-height slice with duplicate hashes. Skip the append when the hash is already tracked; distinct fork hashes at the same height are still kept.
…hs (#2551) stats is a function-local insertStats and stats.report is only called from the main import loop, so every stats write on a path that returns before reaching the loop is dead and never logged: - stats.queued += it.processed() on the first-block future path is not only unreachable for reporting but off by one: it.processed() returns it.index+1, which over-counts by one both when the whole batch is drained (it.index == len(chain) at exhaustion) and when the loop aborts on a non-exempt error (it.index points at the block that was never queued). Both queued counters date back to ff435e0. - stats.queued++ in the tail future loop (which also skipped the block that triggered the queueing) and stats.ignored += it.remaining() on both future paths are written then dropped on return. - stats.ignored += len(it.chain) in the first-block error abort has the same write-then-return shape. Remove all of them. Drop the insertStats.queued field and the "queued" log context in report() that could never fire once the counters are gone, matching upstream geth whose insertStats no longer carries a queued field, and remove the now-unused insertIterator helpers processed() and remaining(). The live stats.ignored accounting (the ErrKnownBlock skip loop that falls through to the import loop and the InsertReceiptChain stats) is untouched.
…chain.go (#2552) Replace direct == / != comparisons against sentinel errors (consensus.ErrPrunedAncestor, consensus.ErrFutureBlock, consensus.ErrUnknownAncestor, ErrKnownBlock, ErrStopPreparingBlock) with errors.Is, which also matches wrapped errors.
) Add regression tests asserting that header verification checks the timestamp first and answers ErrFutureBlock for blocks too far ahead, without requiring their parent to be resolvable. XDPoS v1/v2 (under full verification) order the checks this way; these tests pin the behavior the future-batch tail queueing (queueFutureTail) relies on: children of a future block surface as ErrFutureBlock, not ErrUnknownAncestor. No production code is changed.
|
Important Review skippedToo many files! This PR contains 343 files, which is 243 over the limit of 100. To get a review, reduce the PR to 100 files or fewer by splitting it into smaller PRs or changing its base branch. Upgrade to a paid plan to raise the limit. Usage-priced reviews support at most 300 files. ⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Advanced Run ID: ⛔ Files ignored due to path filters (1)
📒 Files selected for processing (343)
You can disable this status message by setting the Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
…rg, ethereum#19748 ethereum#20506 (#2555) Port upstream go-ethereum fixes ethereum#19748 and ethereum#20506 (fixes the flaky 'Canonical section count mismatch' in TestChainIndexerWithChildren, see upstream issue ethereum#20497): - newHead: on reorg, revert from section (head+1)/sectionSize since the common ancestor head itself is still valid - updateLoop: verify the last stored section head against the canonical chain before processing and after a failed processing, rolling back stale sections so the indexer can never get stuck with an invalid stored section (the root cause of the flaky 'Canonical section count mismatch: have 79, want 78' failure in TestChainIndexerWithChildren) - Sections(): report an up-to-date section count via verifyLastHead - updateLoop: guard SectionHead underflow with section == 0 - chain_indexer_test: sync reorg expectation helper with the new revert semantics
in order to fix fastsync snapshot err
* update reward for devnet and testnet * fix test * update round number again
* fix genesis bug not importing FoundationWalletAddr properly * bump MaxProtectorNodes count * - activate forks for local chain (to match mainnet release) - add reward calc for protector and observer nodes - properly apply chainconfig to puppeth * refactor: improve readablility on reward calculation and add tests * update localchain initial config * fix: properly include epoch input for reward calculation * enable gas2500x on localnet (match next mainnet release)
…reen (#2561) Two test failures that predate the XDPoS schedule work and are unrelated to it. core/vm/privacy/ringct_test.go asserts on the cgo secp256k1 BitCurve that ringct.go is built on, so without cgo - the default on Windows - every test in the file panics. Tag the file cgo so it is compiled only where that curve exists. ethclient/gethclient's TestGethClient leaves the XDCx database's log file open for the lifetime of the node, which keeps t.TempDir's cleanup from removing the directory on Windows. The test itself is platform independent, so skip it there rather than letting the cleanup failure fail the run.
…#2562) XDPoS_v2.chainConfig was only assigned in New and never read. The unexported field had no readers inside or outside the package, so it is pure dead state. Remove the field and its sole assignment; the New parameter is kept because it still backs the nil guard and derives the XDPoS config.
…2563) reorg spawned the removed-logs send while the reborn logs and the canonical logs go out synchronously. A subscriber could therefore observe the logs of the new chain before the removals of the blocks they revert. geth hit the same problem twice: ethereum#14865 introduced `go` for both feeds, 43631aa merged them into one goroutine that sends removals first, and ethereum#19396 dropped the goroutine altogether. This port was left on the first form, and worse: only the removals were asynchronous, so the two feeds did not even agree on the delivery mode. Send the removals synchronously too. event.Feed.Send blocks until a slow subscriber takes the event, which is the trade-off geth accepted in order to get a deterministic order. TestLogReorgs subscribed on an unbuffered channel and only drained it after the import, which now deadlocks; it starts the receiver before the import instead, as geth's testLogReorgs does. Tests: TestReorgDeliversRemovedLogsSynchronously stalls the subscriber on purpose and fails if the reorg returns before the removals were delivered. It fails with the old `go` in place and passes without it.
Use the txpool pending nonce when creating block signer transactions so retries do not collide with an existing pending nonce and trigger replacement transaction underpriced. Co-authored-by: Daniel Liu <[email protected]>
…2223) * feat(consensus): add RPC endpoint to query signing tx count by epoch * Apply suggestion from @Copilot Co-authored-by: Copilot <[email protected]> * Apply suggestion from @Copilot Co-authored-by: Copilot <[email protected]> * Apply suggestion from @Copilot Co-authored-by: Copilot <[email protected]> * Apply suggestion from @Copilot Co-authored-by: Copilot <[email protected]> * fix build issue --------- Co-authored-by: liam.lai <[email protected]> Co-authored-by: Copilot <[email protected]>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Proposed changes
Types of changes
What types of changes does your code introduce to XDC network?
Put an
✅in the boxes that applyImpacted Components
Which parts of the codebase does this PR touch?
Put an
✅in the boxes that applyChecklist
Put an
✅in the boxes once you have confirmed below actions (or provide reasons on not doing so) that