From 7755ee3e4f5ee534252a524a668e58714f944408 Mon Sep 17 00:00:00 2001 From: Tristan-Wilson <87238672+Tristan-Wilson@users.noreply.github.com> Date: Mon, 10 Nov 2025 09:38:28 +0100 Subject: [PATCH 1/7] consensus/misc/eip4844: expose TargetBlobsPerBlock (#32991) Rollups may want to use these to dynamically adjust blobs posted after BPO forks. --- consensus/misc/eip4844/eip4844.go | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/consensus/misc/eip4844/eip4844.go b/consensus/misc/eip4844/eip4844.go index e14d129561..c1a21195e3 100644 --- a/consensus/misc/eip4844/eip4844.go +++ b/consensus/misc/eip4844/eip4844.go @@ -200,6 +200,15 @@ func LatestMaxBlobsPerBlock(cfg *params.ChainConfig) int { return bcfg.Max } +// TargetBlobsPerBlock returns the target blobs per block for a block at the given timestamp. +func TargetBlobsPerBlock(cfg *params.ChainConfig, time uint64) int { + blobConfig := latestBlobConfig(cfg, time) + if blobConfig == nil { + return 0 + } + return blobConfig.Target +} + // fakeExponential approximates factor * e ** (numerator / denominator) using // Taylor expansion. func fakeExponential(factor, numerator, denominator *big.Int) *big.Int { From fbd89be0479f76ff56ccb6f8f2d882f3c38133cf Mon Sep 17 00:00:00 2001 From: sashass1315 Date: Mon, 10 Nov 2025 19:44:31 +0200 Subject: [PATCH 2/7] eth/catalyst: always reset timer after sealing error (#33146) The periodic sealing loop failed to reset its timer when sealBlock returned an error, causing the timer to never fire again and effectively halting block production in developer periodic mode after the first failure. This is a bug because the loop relies on the timer to trigger subsequent sealing attempts, and transient errors (e.g., pool races or chain rewinds) should not permanently stop the loop. The change moves timer.Reset after the sealing attempt unconditionally, ensuring the loop continues ticking and retrying even when sealing fails, which matches how other periodic timers in the codebase behave and preserves forward progress. --- eth/catalyst/simulated_beacon.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/eth/catalyst/simulated_beacon.go b/eth/catalyst/simulated_beacon.go index c10990c233..d9f01240a7 100644 --- a/eth/catalyst/simulated_beacon.go +++ b/eth/catalyst/simulated_beacon.go @@ -280,9 +280,8 @@ func (c *SimulatedBeacon) loop() { case <-timer.C: if err := c.sealBlock(c.withdrawals.pop(10), uint64(time.Now().Unix())); err != nil { log.Warn("Error performing sealing work", "err", err) - } else { - timer.Reset(time.Second * time.Duration(c.period)) } + timer.Reset(time.Second * time.Duration(c.period)) } } } From ca912542591033ab292d1a299c1048cdce9ecece Mon Sep 17 00:00:00 2001 From: Guillaume Ballet <3272758+gballet@users.noreply.github.com> Date: Tue, 11 Nov 2025 03:07:32 +0100 Subject: [PATCH 3/7] build: add wasm targets for keeper (#33124) [powdr](github.com/powdr-labs/powdr) has tested keeper in their womir system and managed to get it to work. This PR adds wasm as a keeper target. There's another plan by the zkevm team to support wasm with wasi as well, so these PR adds both targets. These currently uses the `example` tag, as there is no precompile intefrace defined for either target yet. Nonetheless, this is useful for testing these zkvms so it makes sense to support these experimental targets already. --- build/ci.go | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/build/ci.go b/build/ci.go index 59c948acb3..e589cd2b40 100644 --- a/build/ci.go +++ b/build/ci.go @@ -107,6 +107,18 @@ var ( Tags: "ziren", Env: map[string]string{"GOMIPS": "softfloat", "CGO_ENABLED": "0"}, }, + { + Name: "wasm-js", + GOOS: "js", + GOARCH: "wasm", + Tags: "example", + }, + { + Name: "wasm-wasi", + GOOS: "wasip1", + GOARCH: "wasm", + Tags: "example", + }, { Name: "example", Tags: "example", @@ -331,6 +343,10 @@ func buildFlags(env build.Environment, staticLinking bool, buildTags []string) ( } ld = append(ld, "-extldflags", "'"+strings.Join(extld, " ")+"'") } + // TODO(gballet): revisit after the input api has been defined + if runtime.GOARCH == "wasm" { + ld = append(ld, "-gcflags=all=-d=softfloat") + } if len(ld) > 0 { flags = append(flags, "-ldflags", strings.Join(ld, " ")) } From 5f4cc3f57d737ad124ddb8a23c97f04d7c60a079 Mon Sep 17 00:00:00 2001 From: Matthieu Vachon Date: Tue, 11 Nov 2025 01:57:52 -0500 Subject: [PATCH 4/7] core/state: fixed hooked StateDB handling of `OnCodeChangeV2` (#33148) While updating to latest Geth, I noticed `OnCodeChangeV2` was not properly handled in `SelfDestruct/6780`, this PR fixes this and bring a unit test. Let me know if it's deemed more approriate to merge the tests with the other one. --- core/state/statedb_hooked.go | 4 +-- core/state/statedb_hooked_test.go | 41 +++++++++++++++++++++++++++++++ eth/tracers/native/mux.go | 8 ++++++ 3 files changed, 51 insertions(+), 2 deletions(-) diff --git a/core/state/statedb_hooked.go b/core/state/statedb_hooked.go index 9db201fc2b..50acc03aa8 100644 --- a/core/state/statedb_hooked.go +++ b/core/state/statedb_hooked.go @@ -220,7 +220,7 @@ func (s *hookedStateDB) SelfDestruct(address common.Address) uint256.Int { var prevCode []byte var prevCodeHash common.Hash - if s.hooks.OnCodeChange != nil { + if s.hooks.OnCodeChange != nil || s.hooks.OnCodeChangeV2 != nil { prevCode = s.inner.GetCode(address) prevCodeHash = s.inner.GetCodeHash(address) } @@ -246,7 +246,7 @@ func (s *hookedStateDB) SelfDestruct6780(address common.Address) (uint256.Int, b var prevCode []byte var prevCodeHash common.Hash - if s.hooks.OnCodeChange != nil { + if s.hooks.OnCodeChange != nil || s.hooks.OnCodeChangeV2 != nil { prevCodeHash = s.inner.GetCodeHash(address) prevCode = s.inner.GetCode(address) } diff --git a/core/state/statedb_hooked_test.go b/core/state/statedb_hooked_test.go index bacb7baee1..4ff1023eb2 100644 --- a/core/state/statedb_hooked_test.go +++ b/core/state/statedb_hooked_test.go @@ -122,6 +122,47 @@ func TestHooks(t *testing.T) { sdb.AddLog(&types.Log{ Address: common.Address{0xbb}, }) + + if len(result) != len(wants) { + t.Fatalf("number of tracing events wrong, have %d want %d", len(result), len(wants)) + } + + for i, want := range wants { + if have := result[i]; have != want { + t.Fatalf("error event %d, have\n%v\nwant%v\n", i, have, want) + } + } +} + +func TestHooks_OnCodeChangeV2(t *testing.T) { + inner, _ := New(types.EmptyRootHash, NewDatabaseForTesting()) + + var result []string + var wants = []string{ + "0xaa00000000000000000000000000000000000000.code: (0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470) ->0x1325 (0xa12ae05590de0c93a00bc7ac773c2fdb621e44f814985e72194f921c0050f728) ContractCreation", + "0xaa00000000000000000000000000000000000000.code: 0x1325 (0xa12ae05590de0c93a00bc7ac773c2fdb621e44f814985e72194f921c0050f728) -> (0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470) SelfDestruct", + "0xbb00000000000000000000000000000000000000.code: (0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470) ->0x1326 (0x3c54516221d604e623f358bc95996ca3242aaa109bddabcebda13db9b3f90dcb) ContractCreation", + "0xbb00000000000000000000000000000000000000.code: 0x1326 (0x3c54516221d604e623f358bc95996ca3242aaa109bddabcebda13db9b3f90dcb) -> (0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470) SelfDestruct", + } + emitF := func(format string, a ...any) { + result = append(result, fmt.Sprintf(format, a...)) + } + sdb := NewHookedState(inner, &tracing.Hooks{ + OnCodeChangeV2: func(addr common.Address, prevCodeHash common.Hash, prevCode []byte, codeHash common.Hash, code []byte, reason tracing.CodeChangeReason) { + emitF("%v.code: %#x (%v) ->%#x (%v) %s", addr, prevCode, prevCodeHash, code, codeHash, reason) + }, + }) + sdb.SetCode(common.Address{0xaa}, []byte{0x13, 37}, tracing.CodeChangeContractCreation) + sdb.SelfDestruct(common.Address{0xaa}) + + sdb.SetCode(common.Address{0xbb}, []byte{0x13, 38}, tracing.CodeChangeContractCreation) + sdb.CreateContract(common.Address{0xbb}) + sdb.SelfDestruct6780(common.Address{0xbb}) + + if len(result) != len(wants) { + t.Fatalf("number of tracing events wrong, have %d want %d", len(result), len(wants)) + } + for i, want := range wants { if have := result[i]; have != want { t.Fatalf("error event %d, have\n%v\nwant%v\n", i, have, want) diff --git a/eth/tracers/native/mux.go b/eth/tracers/native/mux.go index 77ab254568..37fc64f3f5 100644 --- a/eth/tracers/native/mux.go +++ b/eth/tracers/native/mux.go @@ -156,6 +156,14 @@ func (t *muxTracer) OnCodeChange(a common.Address, prevCodeHash common.Hash, pre } } +func (t *muxTracer) OnCodeChangeV2(a common.Address, prevCodeHash common.Hash, prev []byte, codeHash common.Hash, code []byte, reason tracing.CodeChangeReason) { + for _, t := range t.tracers { + if t.OnCodeChangeV2 != nil { + t.OnCodeChangeV2(a, prevCodeHash, prev, codeHash, code, reason) + } + } +} + func (t *muxTracer) OnStorageChange(a common.Address, k, prev, new common.Hash) { for _, t := range t.tracers { if t.OnStorageChange != nil { From 7368b34a4beac8ccf2db3529821c9fb2d1a40378 Mon Sep 17 00:00:00 2001 From: Lucia Date: Tue, 11 Nov 2025 21:01:37 +1300 Subject: [PATCH 5/7] core/rawdb: capture open file error and fix resource leak (#33147) --- core/rawdb/eradb/eradb.go | 1 + core/rawdb/freezer_batch.go | 10 ++++++++-- core/rawdb/freezer_table.go | 7 ++++--- 3 files changed, 13 insertions(+), 5 deletions(-) diff --git a/core/rawdb/eradb/eradb.go b/core/rawdb/eradb/eradb.go index 29e658798e..a552b94da9 100644 --- a/core/rawdb/eradb/eradb.go +++ b/core/rawdb/eradb/eradb.go @@ -303,6 +303,7 @@ func (db *Store) openEraFile(epoch uint64) (*era.Era, error) { } // Sanity-check start block. if e.Start()%uint64(era.MaxEra1Size) != 0 { + e.Close() return nil, fmt.Errorf("pre-merge era1 file has invalid boundary. %d %% %d != 0", e.Start(), era.MaxEra1Size) } log.Debug("Opened era1 file", "epoch", epoch) diff --git a/core/rawdb/freezer_batch.go b/core/rawdb/freezer_batch.go index 7e46e49f43..080c0720a1 100644 --- a/core/rawdb/freezer_batch.go +++ b/core/rawdb/freezer_batch.go @@ -51,12 +51,18 @@ func newFreezerBatch(f *Freezer) *freezerBatch { // Append adds an RLP-encoded item of the given kind. func (batch *freezerBatch) Append(kind string, num uint64, item interface{}) error { - return batch.tables[kind].Append(num, item) + if table := batch.tables[kind]; table != nil { + return table.Append(num, item) + } + return errUnknownTable } // AppendRaw adds an item of the given kind. func (batch *freezerBatch) AppendRaw(kind string, num uint64, item []byte) error { - return batch.tables[kind].AppendRaw(num, item) + if table := batch.tables[kind]; table != nil { + return table.AppendRaw(num, item) + } + return errUnknownTable } // reset initializes the batch. diff --git a/core/rawdb/freezer_table.go b/core/rawdb/freezer_table.go index 01a754c5c8..aedb2d8eed 100644 --- a/core/rawdb/freezer_table.go +++ b/core/rawdb/freezer_table.go @@ -1196,8 +1196,7 @@ func (t *freezerTable) sizeNolock() (uint64, error) { } // advanceHead should be called when the current head file would outgrow the file limits, -// and a new file must be opened. The caller of this method must hold the write-lock -// before calling this method. +// and a new file must be opened. This method acquires the write-lock internally. func (t *freezerTable) advanceHead() error { t.lock.Lock() defer t.lock.Unlock() @@ -1218,7 +1217,9 @@ func (t *freezerTable) advanceHead() error { return err } t.releaseFile(t.headId) - t.openFile(t.headId, openFreezerFileForReadOnly) + if _, err := t.openFile(t.headId, openFreezerFileForReadOnly); err != nil { + return err + } // Swap out the current head. t.head = newHead From d8f9801305128711863fdc5657b883afb7075052 Mon Sep 17 00:00:00 2001 From: Michael Kaplan <55204436+michaelkaplan13@users.noreply.github.com> Date: Tue, 11 Nov 2025 09:54:36 -0500 Subject: [PATCH 6/7] rpc: avoid unnecessary RST_STREAM, PING frames sent by client (#33122) Context from Cloudflare blog: https://blog.cloudflare.com/go-and-enhance-your-calm/#reading-bodies-in-go-can-be-unintuitive We were able to reproduce the same issue discussed by Cloudflare in their recent blog post above using the `ethclient`. --- rpc/http.go | 14 +++++++++++--- rpc/http_test.go | 2 +- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/rpc/http.go b/rpc/http.go index f4b99429ef..a74f36a1b0 100644 --- a/rpc/http.go +++ b/rpc/http.go @@ -168,13 +168,21 @@ func newClientTransportHTTP(endpoint string, cfg *clientConfig) reconnectFunc { } } +// cleanlyCloseBody avoids sending unnecessary RST_STREAM and PING frames by +// ensuring the whole body is read before being closed. +// See https://blog.cloudflare.com/go-and-enhance-your-calm/#reading-bodies-in-go-can-be-unintuitive +func cleanlyCloseBody(body io.ReadCloser) error { + io.Copy(io.Discard, body) + return body.Close() +} + func (c *Client) sendHTTP(ctx context.Context, op *requestOp, msg interface{}) error { hc := c.writeConn.(*httpConn) respBody, err := hc.doRequest(ctx, msg) if err != nil { return err } - defer respBody.Close() + defer cleanlyCloseBody(respBody) var resp jsonrpcMessage batch := [1]*jsonrpcMessage{&resp} @@ -191,7 +199,7 @@ func (c *Client) sendBatchHTTP(ctx context.Context, op *requestOp, msgs []*jsonr if err != nil { return err } - defer respBody.Close() + defer cleanlyCloseBody(respBody) var respmsgs []*jsonrpcMessage if err := json.NewDecoder(respBody).Decode(&respmsgs); err != nil { @@ -236,7 +244,7 @@ func (hc *httpConn) doRequest(ctx context.Context, msg interface{}) (io.ReadClos if _, err := buf.ReadFrom(resp.Body); err == nil { body = buf.Bytes() } - resp.Body.Close() + cleanlyCloseBody(resp.Body) return nil, HTTPError{ Status: resp.Status, StatusCode: resp.StatusCode, diff --git a/rpc/http_test.go b/rpc/http_test.go index 6c268b6292..15ddd59bd0 100644 --- a/rpc/http_test.go +++ b/rpc/http_test.go @@ -106,7 +106,7 @@ func confirmHTTPRequestYieldsStatusCode(t *testing.T, method, contentType, body if err != nil { t.Fatalf("request failed: %v", err) } - resp.Body.Close() + cleanlyCloseBody(resp.Body) confirmStatusCode(t, resp.StatusCode, expectedStatusCode) } From 3d2a4cb0532c43c6e34845cd7f21f8e180fa92a8 Mon Sep 17 00:00:00 2001 From: oxBoni Date: Wed, 12 Nov 2025 08:30:16 +0100 Subject: [PATCH 7/7] core: remove unused peek function in insertIterator (#33155) --- core/blockchain_insert.go | 22 ---------------------- 1 file changed, 22 deletions(-) diff --git a/core/blockchain_insert.go b/core/blockchain_insert.go index ac6a156d3e..07a250a1bb 100644 --- a/core/blockchain_insert.go +++ b/core/blockchain_insert.go @@ -131,28 +131,6 @@ func (it *insertIterator) next() (*types.Block, error) { return it.chain[it.index], it.validator.ValidateBody(it.chain[it.index]) } -// peek returns the next block in the iterator, along with any potential validation -// error for that block, but does **not** advance the iterator. -// -// Both header and body validation errors (nil too) is cached into the iterator -// to avoid duplicating work on the following next() call. -// nolint:unused -func (it *insertIterator) peek() (*types.Block, error) { - // If we reached the end of the chain, abort - if it.index+1 >= len(it.chain) { - return nil, nil - } - // Wait for verification result if not yet done - if len(it.errors) <= it.index+1 { - it.errors = append(it.errors, <-it.results) - } - if it.errors[it.index+1] != nil { - return it.chain[it.index+1], it.errors[it.index+1] - } - // Block header valid, ignore body validation since we don't have a parent anyway - return it.chain[it.index+1], nil -} - // previous returns the previous header that was being processed, or nil. func (it *insertIterator) previous() *types.Header { if it.index < 1 {