Skip to content

all: sync with go-ethereum v1.17.6 - #2502

Open
pratikspatil024 wants to merge 1086 commits into
developfrom
upstream-merge-v1.17.4
Open

pratikspatil024 wants to merge 1086 commits into
developfrom
upstream-merge-v1.17.4

Conversation

@pratikspatil024

@pratikspatil024 pratikspatil024 commented Oct 19, 2026 •

Copy link
Copy Markdown
Member

Summary

Brings upstream-merge-v1.17.4 into develop: Bor's go-ethereum base moves from v1.16.8 to v1.17.6, in one PR per upstream release, each reviewed and merged into the sync branch. develop has no commits the branch lacks; it already carries develop at v2.10.3 (#2498).

Merge as a merge commit. Don't squash: squashing collapses upstream's per-commit history and authorship into one Bor commit, which makes future syncs harder.

Step PR
geth v1.16.9 #2308
geth v1.17.0 #2319
geth v1.17.1 #2325
geth v1.17.2 #2328
geth v1.17.3 (three parts) #2340, #2342, #2345
eth/70 (EIP-7975), implemented but not advertised #2341
CachingDB split into MPT and UBT databases (#34700) #2343
geth v1.17.4 #2346
geth v1.17.5 #2354
EIP-2780 and EIP-8037 spec changes (#35318) #2455
geth v1.17.6 #2461
Fixes found during the sync #2494, #2495, #2496, #2497
develop (v2.10.3) back-merge #2498
Stateless compatibility with v2.10.x #2499, #2500
p2p and RPC limits #2489, #2490, #2491

#2487 and #2488 were closed: #2418, which came in with the v2.10.3 back-merge (#2498), already covers them.

Each release's decisions are recorded under docs/upstream-merges/<version>/:

  • ledger.md: every conflict resolution and why;
  • fork-register.md: the upstream fork-gated changes and how Bor gates them;
  • needs-wiring.md: what was adopted but left unwired or declined, with tickets.

Executed tests

Still to do before merge:

Rollout notes

🤖 Generated with Claude Code

pratikspatil024 and others added 30 commits August 10, 2026 15:23
Twenty upstream first-parent commits, `f9417bb27..76e3dc6`. Twenty-two
conflicted paths, and three further breaks that git reported as clean merges.
The one that mattered most was not in a conflict at all.

Upstream decouples chain rewinding from state recovery in the path scheme, so a
deep rollback is performed once at the end rather than block by block. Bor
carried a stateless-node exemption around the old state check, upstream deleted
that check and reintroduced its replacement further down the same function, and
the replacement merged cleanly without the exemption. A stateless node holds no
state by design, so it would have reached the non-genesis crash branch on any
rewind and exited. The exemption is re-applied at the new site, leaving
stateless behaviour exactly as it was and giving every other node the
single-shot rollback. Bor's other local difference here vanished with the block
that carried it.

The deterministic deployment factory now runs during block building, simulation
and tracing rather than during block processing alone, which is the difference
between a producer and its validators agreeing on the state root at the
activation block. It is adopted in bor's block-gated form, and the transition
helper is retired in favour of the pre-execution path that upstream moved it to.
One gap is recorded rather than closed: bor's miner does not call the shared
pre-execution routine at all, inlining its own steps instead, so the fix has no
landing site there. The conflicted region on bor's side is empty, and adding the
step would be authoring consensus-path code rather than resolving a conflict, so
it belongs with the enablement work.

The block access list ordering check becomes strict, so a duplicated address is
rejected as the spec requires. The helper it calls exists upstream but had been
removed here once its last caller went away, so taking the one-line change alone
would not have compiled; the helper is restored along with it.

The access list exchange fix applies to a protocol surface this fork does not
carry, and is declined accordingly; the test that arrived with it outside any
conflict is removed for the same reason. A flag-parsing correction that treats
an explicit false as presence is applied to this fork's own network cases too,
since the neighbouring case had already merged with the new behaviour and one
switch should not mix both.

Verified: build clean after correcting one clean-merge break in the transition
tool; full-tree vet clean apart from the two pre-existing lock-copy findings;
gofmt clean; go mod tidy clean in the main module; and the touched packages all
pass. Three packages fail and each was re-run at the previous batch's commit and
reproduces there with an identical failure set, so none belongs to this batch.
The transition tool was baselined explicitly because this batch edits it. CI
sees none of the three, because its test list filters the command packages.

A separate finding on a live gas-metering path was raised during this batch's
twin scan and deferred to the follow-up list by decision; it is not addressed
here.
Twenty upstream first-parent commits, `76e3dc6b5..6e6fcef`. Thirty-two
conflicted paths, the most of this sync, resolving to its smallest diff: four
upstream commits are declined whole and taken as follow-up work instead.

The batch exists for the new fork stub, which lands gated off. Upstream schedules
it by timestamp; this fork schedules by block, so the field, the activation
helper, the rules flag, the fork-order and compatibility entries, the banner and
the four virtual-machine sites are all converted to the block form used by every
neighbouring fork. One of those, the compatibility entry, had merged cleanly in
the timestamp form and would not have compiled. The gate is nil on all six
surfaces: both sets of chain parameters, both runtime presets and both packaged
genesis files. Upstream enables it from genesis on one development preset; this
fork's development chain stops several forks earlier, and the new fork's
instruction set derives from one it never enables, so it is left nil there too.

The precompile delta against the previous fork is empty, and that was read off
the stub rather than assumed: the new instruction set is the previous one with
nothing enabled on top, and both precompile lookups return the previous fork's
tables, so the P256 verifier is carried forward as required. This fork's own
later forks are matched ahead of it in all three switches, so their precompile
sets cannot be displaced. Two local guards fired on the new rules field and were
worked through rather than silenced: the multi-client precompile checklist, and
the classification of every fork against the serial and parallel state
processors, where a stub with no state-processor branch is recorded as absent
from both.

Of the four declined commits, three had already merged part of themselves
cleanly, so declining them file by file left the other half stranded: a whole
new peer-scoring package with references bleeding into merged code, an
access-list field this fork removed long ago leaving a dangling reference and
unused imports, and a test-harness accessor for a field this fork's environment
type does not have. Each was reverted in full instead. A fourth commit was
declined only because it shares a file with two of those, and keeping its
configuration half alone would have shipped a command-line flag wired to
nothing.

The largest decline is the intrinsic-gas and gas-budget rework, deferred by
decision to its own change. It is structural rather than a specification tweak,
and it quietly drops one arm of a transaction gas-limit cap that is live on both
production networks. Everything in it is gated behind a fork that is disabled
here, so deferring it changes no behaviour today. Two neighbouring commits that
share files with it were checked against its shape, found independent, and
re-applied afterwards.

Also taken: a cryptography library bump, aligned across both modules and trimmed
to exactly that change; refreshed builder contract addresses and bytecode, copied
verbatim rather than retyped; a gas-budget cap in the execution runtime; charging
the calldata floor when it exceeds regular gas; and draining oversized protocol
messages before rejecting them rather than after.

Verified: build clean after fixing two clean-merge breaks; full-tree vet clean
apart from the two pre-existing lock-copy findings; formatting and module
tidiness clean; and the touched packages all pass, including the full core suite.
One package fails with the standing signature-matched panic that continuous
integration does not see.
Twenty upstream first-parent commits, `6e6fcef0b..81ab8b5`. Forty-one
conflicted paths, the widest set of this sync, resolving to its smallest result:
eleven files. One forty-seven-file commit and five dependents are declined
together.

The large one implements the sparse blob pool, relaying blob cells rather than
whole blobs over a new protocol version. It is declined on two independent
grounds, either sufficient on its own. This fork still speaks the two older
protocol versions, having declined the two intervening ones with recorded
reasoning about state-sync receipt exclusion, so a third cannot precede them;
and the cache file this commit extends by two hundred lines does not exist here,
having been declined earlier. That makes four deferrals on the same protocol
surface, and the divergence is compounding enough to deserve one deliberate
decision rather than another batch-by-batch deferral. Two further commits fall
with it because the only files they touch are files it creates.

The new fork stub gains a correction: its instruction set now derives from the
preceding fork rather than skipping back one further, which is right, since it
follows that fork and should inherit its opcodes. The precompile finding
recorded when the stub landed is unaffected, and was re-checked rather than
assumed: the preceding fork has no precompile branch of its own and falls
through to the same table the stub returns explicitly, so the two share a set
and the delta between them remains empty.

Six other commits are declined as consequences of earlier decisions rather than
new judgements: two belong to the engine-API group already set aside, one adds
an access list to the chain export format from the declined cluster, one edits a
function introduced by the deferred gas-metering rework, one has no landing site
because this fork's chain object holds no such cache, and one is entirely test
files this fork keeps deleted. That last one also adds a new test which
references a helper from a removed file, so it joins the same orphan family.

A further pair is declined as twins already present: this fork implements both
the garbage-collection knob and the cache-derived tuning independently, in its
own command-line surface. Adopting upstream's would leave two competing knobs
across two surfaces.

Adopted, in this fork's shape: the snap-sync pivot is no longer advanced once it
has been committed. The upstream condition also consults a helper that lives in
a file renamed away here, so only the commitment guard is taken — the field
already exists and the identical guard is already used elsewhere in the forked
downloader, so this aligns two paths that had drifted apart.

Verified: build clean after three revert rounds driven by the compiler, each one
a commit whose other half had merged cleanly; full-tree vet clean apart from the
two pre-existing lock-copy findings; formatting and module tidiness clean; and
the touched packages all pass, including the full core, eth and miner suites.
One package fails with the standing signature-matched panic that continuous
integration does not see.
Ten upstream first-parent commits, `81ab8b594..9621c6a`, closing this sync.
Eighteen conflicted paths resolving to ten files — the smallest batch, the only
one to build on the first attempt, and the only one where no declined commit
left an auto-merged half behind.

The version file moves to the release value. It had merged in as an unstable
snapshot at the start of this sync and was deliberately left alone until the
commit that stabilises it, which is the last one in the range.

The one commit needing real analysis coordinates the prefetcher with the main
executor: the processor publishes the index it is executing, prefetch workers
skip anything already reached, and heavy transactions are promoted to the front
of the queue. An earlier batch had a case where upstream turned out to be
converging on this fork's own ordering, so that was checked first. This is not
that case. Both interfaces here are diverged in both directions rather than by
the added parameter alone; the published index has no sound meaning against
this fork's parallel executor, which runs transactions out of order and
speculatively, so supplying one from the serial path only would be a silently
wrong signal on the path that matters; and this fork's prefetcher is
stream-based, its workers carrying arrival order rather than block position,
with a second caller that has no block to sort at all. Declined whole, with the
port shape recorded.

Adopted, in this fork's shape: block validation now computes the derivable
header fields concurrently with the state root, with this fork's existing timer
moved to follow the root computation to its new site, and the extracted helper
losing the parameter only the declined access-list branch used. Error
precedence is unchanged.

A downloader fix was applied to this fork's twin rather than to the file
upstream changed, which was renamed away here long ago. The twin carried the
same defect — a commitment flag stored outside the lock every neighbouring
pivot transition uses — on a path that is live, and whose reader was aligned
with upstream only one batch ago. The sole caller holds no lock there.

Also taken: the sidecar size fix, which is version-conditional and therefore
correct for both sidecar shapes even though the pool half of the same commit is
declined against a shape this fork does not have; a bearer-token comparison
that was case-insensitive when tested but case-sensitive when stripped; and a
compression dependency bump, noting that upstream pinned an unreleased revision
rather than a tagged one.

Declined besides: a fetcher fix whose only file belongs to a declined feature,
a reorg-depth fix from the engine-API group, the pool half of the sidecar
commit, and a memory-limit guard that has nowhere to land because this fork
replaced that whole configuration path with its own.

The twin scan found three and resolved them three different ways — one fixed,
one with nowhere to land, and one where this fork's own constant carries the
same off-by-one upstream corrected. That last is left alone and written down:
it changes accept and reject behaviour on a constant this fork authored, which
is not something to settle on an upstream merge.

Verified: build clean on the first attempt; full-tree vet clean apart from the
two pre-existing lock-copy findings; formatting and module tidiness clean; the
touched packages all pass, including the full core and eth suites; and the race
detector was run over both the newly concurrent validation path and the changed
downloader lock ordering. Three packages fail with the standing
signature-matched failures that continuous integration does not see.
Documentation only; no code changes. Covers all six batches of this milestone,
and with them the merge work is complete: the branch carries upstream history
through the release tag, in six batches, each a single merge commit with its
reasoning recorded.

These four files were kept out of the tree until now on purpose, so that no
merge commit carried documentation churn alongside its conflict resolutions.

The milestone's weight sits in four decisions.

The new stub fork was the reason the middle batch existed. Upstream schedules it
by timestamp; this fork schedules by block, so the field, the activation helper,
the rules flag, the ordering and compatibility entries, the banner and the four
virtual-machine sites were all converted — including one compatibility entry that
had merged cleanly in the timestamp form and would not have compiled. The gate is
nil on all six surfaces. Its precompile delta against the preceding fork is
empty, and that was read off the code twice rather than assumed once: a later
batch rebased the stub's instruction set onto the preceding fork, which moved the
basis the first check had been made against, so the check was repeated against
the new basis. Two local guards fired on the new rules field and were worked
through rather than silenced.

The sparse blob pool was declined, and with it the two commits whose only files
it creates. It is the fourth deferral on the same protocol surface; that
compounding divergence is now written down as deserving one deliberate decision
rather than a fifth deferral.

The intrinsic-gas and gas-budget rework was deferred to its own change by
operator decision. It is structural rather than a specification tweak, and it
quietly drops one arm of a transaction gas-limit cap that is live on both
production networks. Everything in it is gated behind a fork that is disabled
here, so deferring it changes no behaviour today — but the ordering matters and
is recorded: the same upstream change rewrote the tests that a separate deferred
item wants to restore, so restoring those first would mean restoring tests for a
shape this fork does not have.

The prefetcher coordination was declined last, after being checked against an
earlier case in this same sync where upstream turned out to be converging on this
fork's own ordering. It is not that case, for three independent reasons recorded
in full, and the port shape is written down rather than the refusal alone.

One live-path finding was surfaced during the sync and deferred by operator
decision to work on top of this milestone. It concerns the ordering of a state
read against a gas guard in a storage-write cost function, is described here in
neutral post-fix terms, and is tracked with the other follow-ups.

Everything intentionally not adopted is in the backlog file, with what a future
adoption would require. Nothing was dropped silently.
This PR updates some descriptions of snap sync v2, attaching two unit
tests.
This PR introduces the functionalities to persist the local-built bad
blocks alongside additional execution details.
…5501)

`testing_buildBlockV1` decodes `targetGasLimit` from the payload
attributes but does not pass it to `miner.BuildPayloadArgs`. The miner
then falls back to its configured gas ceiling, so the field is silently
ignored. The engine API path (`forkchoiceUpdated`) already passes it
through.

This matters for fixture generation in ethereum/execution-apis, where
`testing_buildBlockV1` builds Amsterdam test blocks and the gas limit
must honor the CL-provided target (see ethereum/execution-apis#857 and
ethereum/execution-apis#862).

The new test builds an Amsterdam block with a target inside the
per-block adjustment bound and checks the payload hits it exactly.
…r cancellation (#35515)

Close the started signal only after the fetchers are registered on
cancelWg, so suspend's Cancel actually waits for them instead of racing
the registration.
…35473)

#35388 keys the cache on `keccak256(address, input)`. Hashing the input
is most of the cost of a lookup, and it scales with input size, so a
large input is expensive to look up even when the result is trivial.
That is why several precompiles had to opt out to stay ahead of it.

@ayamiyaguchi spotted this and wrote the first commit here, which
excluded the precompiles the key cost was hurting most. This takes the
same finding in a different direction by making the key cheap in the
first place, so those precompiles do not need excluding.

The solution here is to key on the input bytes directly, plus three
changes that follow from it:

1) Entries used to share one LRU, so a high-volume precompile could
evict the pairing and modexp results the cache exists to hold. Each
precompile now gets its own.

2) Now that the key is the input, entries run from tens of bytes to
kilobytes, and a count means very different memory depending on the mix.
Each precompile gets 1 MiB of keys and values.

3) A precompile is cached only if it says so, and can narrow an input to
the bytes that determine the result via `NormalizeInput` so padding
lands on the entry the unpadded call already made.

### Benchmarks

Medians of five runs. 

#### Lookup versus running the precompile, at real vector sizes

| precompile           |  input |     #35388 |    this PR |       run |
|----------------------|--------|------------|------------|-----------|
| ECREC                |    128 |     480 ns |      55 ns |   18.2 µs |
| SHA256               |    128 | not cached |      58 ns |     79 ns |
| RIPEMD160            |    128 | not cached |      55 ns |    454 ns |
| ID                   |    128 | not cached | not cached |     16 ns |
| MODEXP               |    609 |     1.1 µs |     128 ns |    2.9 µs |
| BN254_ADD            |    128 |     478 ns |      54 ns |    1.0 µs |
| BN254_MUL            |     96 |     279 ns |      52 ns |   13.4 µs |
| BN254_PAIRING        |    384 |     698 ns |      85 ns |  490.1 µs |
| BLAKE2F              |    213 |     486 ns |      67 ns |    118 ns |
| KZG_POINT_EVALUATION |    192 |     488 ns |      61 ns |  785.8 µs |
| BLS12_G1ADD          |    256 |     697 ns |      68 ns |    1.9 µs |
| BLS12_G1MSM          |    160 |     488 ns |      60 ns |   95.4 µs |
| BLS12_G2ADD          |    512 |     911 ns |     103 ns |    2.9 µs |
| BLS12_G2MSM          |    288 |     708 ns |      74 ns |  181.3 µs |
| BLS12_PAIRING_CHECK  |    384 |     713 ns |      85 ns |  445.6 µs |
| BLS12_MAP_FP_TO_G1   |     64 |     282 ns |      45 ns |   30.7 µs |
| BLS12_MAP_FP2_TO_G2  |    128 |     490 ns |      55 ns |  135.0 µs |
| P256VERIFY           |    160 |     494 ns |      60 ns |   33.6 µs |

RIPEMD160 wasn't cached before and a lookup now costs 55 ns against 454
ns to run it. BN254_ADD was cached previously, but at 478 ns to look up
against a 1 µs run the cache was barely paying for itself. With this
change, the lookup is now 54 ns and much more worth it.

#### The same measurement at the largest eligible input, 8 KiB

| precompile           |     #35388 |          this PR |       run |
|----------------------|------------|------------------|-----------|
| ECREC                |    12.9 µs |            74 ns |    131 ns |
| SHA256               | not cached |           1.1 µs |    2.6 µs |
| RIPEMD160            | not cached |           1.2 µs |   17.9 µs |
| ID                   | not cached |       not cached |    969 ns |
| MODEXP               |    13.0 µs |            56 ns |     50 ns |
| BN254_ADD            |    12.9 µs |            67 ns |     60 ns |
| BN254_MUL            |    12.9 µs |            56 ns |    6.4 µs |
| BN254_PAIRING        |    12.8 µs | 5 ns, not cached |      2 ns |
| BLAKE2F              |    12.9 µs | 5 ns, not cached |      1 ns |
| KZG_POINT_EVALUATION |    12.9 µs | 4 ns, not cached |      1 ns |
| BLS12_G1ADD          |    12.8 µs | 5 ns, not cached |      1 ns |
| BLS12_G1MSM          |    13.0 µs | 4 ns, not cached |      1 ns |
| BLS12_G2ADD          |    13.0 µs | 4 ns, not cached |      1 ns |
| BLS12_G2MSM          |    12.9 µs | 4 ns, not cached |      1 ns |
| BLS12_PAIRING_CHECK  |    13.0 µs | 5 ns, not cached |      1 ns |
| BLS12_MAP_FP_TO_G1   |    13.0 µs | 4 ns, not cached |      1 ns |
| BLS12_MAP_FP2_TO_G2  |    12.8 µs | 4 ns, not cached |      1 ns |
| P256VERIFY           |    13.0 µs | 4 ns, not cached |      1 ns |

The `#35388` column is flat at ~13 µs because the key is a hash of the
input and does not depend on which precompile receives it. In the `this
PR` column, the number beside "not cached" is the cost of deciding not
to build a key: those precompiles require an exact length, so an 8 KiB
input is one they will reject, and there is no result worth keying. The
`run` column here is mostly a length rejection rather than work, so it
is context for the other two columns rather than a comparison.

---------

Co-authored-by: aya <aya@ethereum.org>
Co-authored-by: Gary Rong <garyrong0905@gmail.com>
StateSize is a development tool for calculating and tracking the size of
the state. It was requested by ethPandaOps a while ago, but it has since
been superseded by another approach that captures state changes via a
live tracer. Therefore, this tool can be retired to reduce maintenance
overhead.
pebble v2's LevelMetrics.TablesSize is already int64, so the int64()
conversion in the actual-data-size gauge is a no-op that golangci-lint's
unconvert linter rejects.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…ync target (#35433)

Fixes #35418.

After a restart, the syncer sets the finalized marker to head−64 and the
safe marker to head−32 on every downloader sync event, ignoring epoch
boundaries. Since this service is registered unconditionally and
`api_backend` serves `CurrentFinalBlock()` verbatim,
`eth_getBlockByNumber("finalized")` can return a mid-epoch block that
was never finalized and can still be reorged.

The synthesized markers exist to make `finalized`/`safe` usable when no
consensus client is attached. This change scopes them to exactly that
case: they are only set when an explicit sync target has been specified
(`--synctarget`), which is the only mode where no CL supplies real
checkpoints. Normal nodes now never override consensus-client
checkpoints.

`TestSyncerDoesNotInventFinalityMarkers` syncs a node to head with no CL
finality input and asserts the chain's finalized/safe markers stay
unset; it fails on master (finalized invented at head−64) and passes
with this change.

---------

Co-authored-by: SillyZir <269283839+SillyZir@users.noreply.github.com>
Co-authored-by: Jonny Rhea <5555162+jrhea@users.noreply.github.com>
Co-authored-by: rjl493456442 <garyrong0905@gmail.com>
This PR explicitly clears the referenced block access list at the end of
each transaction. This is essential because accounts are shadow-copied
into the global block access list, and it prevents accidental mutations
through stale references in StateDB.
`BlobPool.Init` builds the lookup, index and store without holding
`p.lock`, and `eth/backend.go` publishes the pool to `blobpool.NewCache`
before `txpool.New` runs Init. Cache.update spawns a goroutine calling
`getByVhash`, so it can read the pool mid-construction:

```
    panic: runtime error: invalid memory address or nil pointer dereference
    [signal SIGSEGV: segmentation violation code=0x1 addr=0x28]
    blobpool.(*BlobPool).getByVhash(...)  blobpool.go:1303
    blobpool.(*Cache).update.func1()      cache.go:429
```

`Init` fills the lookup inside `billy.Open`, whose index callback runs
`parseTransaction` -> `trackTransaction`, and assigns `p.store` only
once `billy.Open` returns. For that window a lookup hit names a
transaction whose store does not exist yet, and `p.store.Get`
dereferences nil.

Build the cache after `txpool.New` so no reader exists while `Init` runs
-- `getByVhash` has exactly one caller -- and have `getByVhash` read the
store under the same lock as the lookup, returning nil when it is not
set.

A benchmark harness that restarts the client once per test hit this on
1-4% of starts; a node that starts once rarely will.
…ocol version (#35524)

eth/72 announces blob transactions without the blob payload while eth/71
includes it, so the same transaction is announced with different
sizes. Compare each announcement against the size expected for that
peer's version instead of a single size so that honest peers on either version
are no longer dropped on delivery.
pratikspatil024 and others added 10 commits October 1, 2026 14:47
Brings in #2455's merge into the base (174b61b) so this PR's diff is only
v1.17.6 again.

GitHub rebased #2455 onto the base when #2354 merged, so its commits
(b4a3d86, 89d2fd3, ada1fc7) are new copies of the ones this branch
already contains via 754d732. A normal three-way merge re-applies the
same #2455 hunks and conflicts wherever v1.17.6 changed them further.

This merge keeps this branch's tree unchanged (-s ours), and that is the
correct result. The merged base's tree equals ada1fc7, which differs from
754d732 (an ancestor of this branch) only in core/vm/gen_dispatch/main.go
and core/vm/interpreter_dispatch.go, where the rebase restored #2346's
RegularGas form. This branch needs its own form there (ExecutionGas,
mirroring this branch's Run), which it already has. Nothing else in the
base is missing here.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
core, eth, params: merge geth v1.17.6 (v1.17.6 sync)
Brings the base up to date with develop at 1cdf43c, including the
v2.10.3 back-merge (#2493).

Conflicts resolved in 22 files; develop-only code (eth/sequencer, the
miner's adoption seeding, and develop's tests) ported to the go-ethereum
APIs the base already carries. eth_sendRawTransactionSync accepts its
timeout as a JSON integer or a hex string (TxSyncTimeout). Full decision
list in the PR description.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…2494)

Stateless nodes don't create a transaction pool, so eth.txPool is nil.
Most TxPool methods already return a safe default on a nil receiver.
PoolNonce, Status, Sync and Clear didn't, and the first three are reachable
over RPC (eth_getTransactionCount "pending", transaction status lookups,
debug_clearTxpool). Each call hit a nil dereference that the RPC layer
recovered and logged as a crash. SetSpeculativeState gets the same guard
for consistency.

POS-3741

Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…st (#2495)

FilterTxConditional removed transactions whose PIP-15 options no longer
hold, but didn't subtract their cost from the list's totalcost, unlike
every other removal path. The inflated total is the sender's committed
spend in transaction validation, so later transactions from that sender
could be rejected for insufficient funds they actually had.

POS-3704

Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* miner: don't seal a block after a state read failure

If a database or trie-node read fails while a block is built, the StateDB
records the error and the block ends up computed over incomplete state.
Upstream #35427 stops sealing in that case, but only in generateWork,
which Bor's block production doesn't use.

Check StateDB.Error before sealing on every path: generateWork (upstream's
spot), commit, and both pipelined-SRC points (commitPipelined and
finalizeCurrent). The pipelined path matters most: it announces a block
before writing it, so a read failure there would send peers an invalid
block. Production pipelining is currently disabled.

POS-3739

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* miner: check state errors in the sequential fallback and log skipped seals

fallbackToSequential computes the root inline when the speculative setup
fails, then sealed the block without checking StateDB.Error. Check it
after IntermediateRoot, as the other paths do.

Callers discard the errors from commit and commitPipelined, so log the
block number and the underlying error where a state read failure stops
sealing.

POS-3739

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* internal/cli: add bor db pebble-upgrade

Existing bor databases are in pebble's legacy v1 format and keep opening
with pebble v1. New databases use pebble v2. This adds the explicit
upgrade: `bor db pebble-upgrade --datadir <dir>` ratchets
<datadir>/bor/chaindata to FormatFlushableIngest, the oldest format pebble
v2 opens, via ethdb/pebble.Upgrade. Older bor binaries can still open the
result.

The command fails while the node is running, because pebble holds the
database lock. It also refuses LevelDB and missing databases, and logs the
format before and after along with the elapsed time.

POS-3746

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* internal/cli: test db command registration and drop duplicate format reads

Cover the "db" and "db pebble-upgrade" registrations, their help text,
and flag-parse errors. Drop the command's own format reads before and
after the upgrade: pebble.Upgrade already reads the format, logs it
before and after, and returns early on a database pebble v2 can open.

POS-3746

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…10.3

Merge develop (v2.10.3) into upstream-merge-v1.17.4
* core/vm: keep the system-call transfer before Amsterdam

Upstream #33741 skips the value transfer when the caller is the system
address, so EIP-7928 block access lists leave it out. The zero-value
transfer was the only read of the system account in the EIP-2935 system
call, so a node built from the upstream merge stops recording that
account's proof in the witnesses it builds. Stateless nodes on v2.10.x
still read the account and fail those witnesses with a missing trie node
under 0xff...fe.

Keep the transfer for system calls until Amsterdam is active. Before
Amsterdam that is v2.10.x's behaviour; after it, upstream's.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* core/vm: gate the system-call balance check with the transfer

Before Amsterdam the system-call transfer runs again, but the balance
check still skipped every system call, so a value-bearing call from the
system address (reachable through RPC state overrides) could subtract
more than its balance. Gate both on the same condition, which restores
the v2.10.x ErrInsufficientBalance before Amsterdam and keeps upstream's
skip from Amsterdam on.

Add a test across the Amsterdam activation block (N-1, N, N+1) for both
zero-value and unfunded value calls.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* core/vm: gate upstream's skipped state reads behind Hampi

Upstream now returns from some gas functions before state reads whose
result can no longer change the outcome: SSTORE and SELFDESTRUCT in a
static context, CALL with value in a static context, SELFDESTRUCT to a
cold beneficiary without gas for the access, and CALL variants that run
out of gas ahead of the target's code lookup. Gas and results are the
same either way, but the skipped reads leave the witness without data
stateless nodes on v2.10.x still read.

Keep those reads until Hampi, which already gates the PIP-88 SSTORE read
ordering for the same reason. Amsterdam also skips them, since EIP-7928
keeps such reads out of the block access list.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* core/vm: read call targets once and pin both skipped-read forks

Before Hampi and Amsterdam the EIP-7702 call helper read the target code
early for the witness and then again for delegation parsing, recording
it twice. Reuse the first read and fetch after charging only when the
skipped reads are enabled.

TestHampiSkippedReads now checks that every pre-Hampi frame still fails,
in the opcode body or on the gas charge. TestAmsterdamSkipsCallVariantReads
covers the Amsterdam side of skipsDoomedReads with Hampi unscheduled, at
blocks N-1, N and N+1.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@codecov

codecov Bot commented Oct 19, 2026 •

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 38.86256% with 387 lines in your changes missing coverage. Please review.
✅ Project coverage is 58.82%. Comparing base (1cdf43c) to head (6b214d0).
⚠️ Report is 4 commits behind head on develop.

Files with missing lines Patch % Lines
core/blockchain.go 39.34% 72 Missing and 2 partials ⚠️
accounts/usbwallet/ledger.go 0.00% 41 Missing ⚠️
beacon/engine/bapl_encode.go 0.00% 40 Missing ⚠️
accounts/abi/bind/v2/util.go 0.00% 18 Missing ⚠️
consensus/beacon/consensus.go 5.26% 18 Missing ⚠️
beacon/blsync/engineclient.go 0.00% 17 Missing ⚠️
consensus/misc/eip4844/eip4844.go 26.08% 15 Missing and 2 partials ⚠️
...v2/internal/contracts/nested_libraries/bindings.go 0.00% 16 Missing ⚠️
beacon/engine/epe_encode.go 73.33% 10 Missing and 6 partials ⚠️
...unts/abi/bind/v2/internal/contracts/db/bindings.go 0.00% 12 Missing ⚠️
... and 31 more

❌ Your patch check has failed because the patch coverage (38.86%) is below the target coverage (90.00%). You can increase the patch coverage or adjust the target coverage.

Additional details and impacted files

Impacted file tree graph

@@             Coverage Diff             @@
##           develop    #2502      +/-   ##
===========================================
+ Coverage    57.76%   58.82%   +1.06%     
===========================================
  Files          966      994      +28     
  Lines       176609   185020    +8411     
===========================================
+ Hits        102025   108847    +6822     
- Misses       68921    70005    +1084     
- Partials      5663     6168     +505     
Files with missing lines Coverage Δ
accounts/abi/bind/backends/simulated.go 60.68% <100.00%> (ø)
accounts/abi/bind/v2/lib.go 57.98% <100.00%> (+2.42%) ⬆️
accounts/abi/pack.go 80.76% <100.00%> (ø)
accounts/abi/reflect.go 89.93% <100.00%> (ø)
accounts/abi/type.go 86.48% <100.00%> (+0.04%) ⬆️
accounts/abi/unpack.go 80.41% <100.00%> (ø)
accounts/accounts.go 100.00% <100.00%> (ø)
accounts/keystore/keystore.go 77.01% <100.00%> (+0.14%) ⬆️
accounts/keystore/watch.go 73.75% <ø> (ø)
accounts/manager.go 6.00% <100.00%> (+6.00%) ⬆️
... and 74 more

... and 348 files with indirect coverage changes

Files with missing lines Coverage Δ
accounts/abi/bind/backends/simulated.go 60.68% <100.00%> (ø)
accounts/abi/bind/v2/lib.go 57.98% <100.00%> (+2.42%) ⬆️
accounts/abi/pack.go 80.76% <100.00%> (ø)
accounts/abi/reflect.go 89.93% <100.00%> (ø)
accounts/abi/type.go 86.48% <100.00%> (+0.04%) ⬆️
accounts/abi/unpack.go 80.41% <100.00%> (ø)
accounts/accounts.go 100.00% <100.00%> (ø)
accounts/keystore/keystore.go 77.01% <100.00%> (+0.14%) ⬆️
accounts/keystore/watch.go 73.75% <ø> (ø)
accounts/manager.go 6.00% <100.00%> (+6.00%) ⬆️
... and 74 more

... and 348 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

…letes (#2489)

* p2p, p2p/rlpx: bound the frame size until the protocol handshake completes

Reject frames larger than the base protocol message limit before their body is buffered while the devp2p Hello is being read, and lift the limit once it is done.

* p2p, p2p/rlpx: test the frame limit edges and that it is lifted after the handshake

Cover the largest accepted frame, the first rejected one, the limit being lifted once the protocol handshake is done, and setting the limit before the encryption handshake.
* crypto/blake2b: run long F calls in preemptible chunks

Port of ethereum/go-ethereum#35550. F calls with more than 4090 rounds run the assembly rounds in chunks, so the goroutine can be preempted between them. The output is unchanged.

* crypto/blake2b: skip the chunking tests without AVX2

* ci: require the blake2b AVX2 chunking and preemption tests to pass
…2491)

* eth/filters, internal/cli: bound the memory held by polling filters

Limit the number of installed polling filters, the events buffered per filter and the memory buffered across all filters. A filter that overflows is cancelled and reports an error on its next poll. The limits are configurable with rpc.maxfilters, rpc.maxfilteritems and rpc.maxfilterbuffer.

* eth/filters, internal/cli: account for decoded transaction memory and seed HCL filter defaults

Charge pending transactions for the slices the decoder allocates for authorizations and access tuples, including their spare capacity. Start the HCL config loader from the polling filter defaults, so a file that omits the settings no longer decodes them as zero.

* eth/filters, internal/cli: test filter removal, reservation, size estimates and the new flags

Cover timeout and uninstall cleanup, subscription cancellation after an overflow or when a subscription ends, the enqueue contract, slot reservation, the estimate helpers, the buffer size boundary and flag registration.

* eth/filters, internal/cli: charge hash buffer slack, report budget exhaustion and oversized buffer separately

* eth/filters, internal/cli: move polling filter bookkeeping and flags into helpers
* eth/sequencer: snapshot the chain reader under the publisher mutex (#2504)

readTail, recoverSealed and the two seal-gate verdict paths read p.chain
outside p.mu while tests swap the field on a live publisher, which the
nightly race run flagged on develop (TestTwinsNeverBothBroadcast).
Production assigns the field only at construction, but take the snapshot
under the lock like the neighbouring state so the invariant does not
depend on how the field is set.

* ci: run kurtosis e2e against the rio-at-genesis branches (#2508)

* ci: run kurtosis e2e against the rio-at-genesis branches (#2508)

* ci: shard unit tests, fix Go cache, and speed up slow tests

Run unit tests as 4 parallel shards (round-robin over packages), still
-p 1 inside each shard, and keep a unit-tests aggregate check under the
old name. Compile test binaries in parallel before the serial run so it
hits the build cache, and fail on invalid TEST_SHARD/TEST_SHARDS for
test, test-build and test-race instead of testing only the root package.
Run the blake2b AVX2 check in one shard only.

Replace the duplicate setup-go + actions/cache restore (which conflicted
and never saved) with a shared setup-go action: a module cache keyed on
go.sum and a unit-test build cache, both saved only from develop/master
pushes by a test-cache job.

Speed up the slowest tests without reducing what PR CI runs:
- rlp/rlpgen: pkgclash fixture uses core/types vs beacon/types instead
  of bor's eth package, which was type-checked from source (~208s).
- eth/fetcher: per-fetcher gatherSlack (default unchanged); only the four
  tests that import many blocks one at a time shorten it.
- consensus/bor: the milestone fetch timeout is a parameter so the
  timeout test does not wait 30s; production still passes 30s.
- eth: milestone/checkpoint tests mine to block 14 without the 4s
  sprint-start delay.
- miner: goroutine-count polling with a 1s settle window instead of fixed
  sleeps, and independent prefetch/pipeline tests run in parallel.

---------

Co-authored-by: Pratik Patil <pratikspatil024@gmail.com>
@pratikspatil024
pratikspatil024 marked this pull request as ready for review October 21, 2026 04:42
Copilot AI balanced review requested due to automatic review settings October 21, 2026 04:42

@claude claude Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Claude Code Review

This repository is configured for manual code reviews. Comment @claude review for a one-time review, or @claude review always to subscribe this PR to a review on every future push.

Tip: disable this comment in your organization's Code Review settings.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot encountered an error and was unable to review this pull request. You can try again by re-requesting a review.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.