From 6f8e28b4aab10c07fffef02823810a1dfaa06617 Mon Sep 17 00:00:00 2001 From: Guillaume Ballet <3272758+gballet@users.noreply.github.com> Date: Tue, 30 Sep 2025 12:50:20 +0200 Subject: [PATCH 01/23] go.mod, cmd/keeper/go.mod: upgrade victoria metrics dependency (#32720) This is required for geth to compile to WASM. --- cmd/keeper/go.mod | 4 ++-- cmd/keeper/go.sum | 14 ++++---------- go.mod | 4 ++-- go.sum | 10 ++++------ 4 files changed, 12 insertions(+), 20 deletions(-) diff --git a/cmd/keeper/go.mod b/cmd/keeper/go.mod index d1649da43f..16094d16b1 100644 --- a/cmd/keeper/go.mod +++ b/cmd/keeper/go.mod @@ -9,7 +9,7 @@ require ( require ( github.com/StackExchange/wmi v1.2.1 // indirect - github.com/VictoriaMetrics/fastcache v1.12.2 // indirect + github.com/VictoriaMetrics/fastcache v1.13.0 // indirect github.com/bits-and-blooms/bitset v1.20.0 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/consensys/gnark-crypto v0.18.0 // indirect @@ -24,7 +24,7 @@ require ( github.com/ferranbt/fastssz v0.1.4 // indirect github.com/go-ole/go-ole v1.3.0 // indirect github.com/gofrs/flock v0.12.1 // indirect - github.com/golang/snappy v0.0.5-0.20220116011046-fa5810519dcb // indirect + github.com/golang/snappy v1.0.0 // indirect github.com/holiman/bloomfilter/v2 v2.0.3 // indirect github.com/holiman/uint256 v1.3.2 // indirect github.com/klauspost/cpuid/v2 v2.0.9 // indirect diff --git a/cmd/keeper/go.sum b/cmd/keeper/go.sum index e3bc204ba8..3eaef469dc 100644 --- a/cmd/keeper/go.sum +++ b/cmd/keeper/go.sum @@ -2,15 +2,14 @@ github.com/DataDog/zstd v1.4.5 h1:EndNeuB0l9syBZhut0wns3gV1hL8zX8LIu6ZiVHWLIQ= github.com/DataDog/zstd v1.4.5/go.mod h1:1jcaCB/ufaK+sKp1NBhlGmpz41jOoPQ35bpF36t7BBo= github.com/StackExchange/wmi v1.2.1 h1:VIkavFPXSjcnS+O8yTq7NI32k0R5Aj+v39y29VYDOSA= github.com/StackExchange/wmi v1.2.1/go.mod h1:rcmrprowKIVzvc+NUiLncP2uuArMWLCbu9SBzvHz7e8= -github.com/VictoriaMetrics/fastcache v1.12.2 h1:N0y9ASrJ0F6h0QaC3o6uJb3NIZ9VKLjCM7NQbSmF7WI= -github.com/VictoriaMetrics/fastcache v1.12.2/go.mod h1:AmC+Nzz1+3G2eCPapF6UcsnkThDcMsQicp4xDukwJYI= +github.com/VictoriaMetrics/fastcache v1.13.0 h1:AW4mheMR5Vd9FkAPUv+NH6Nhw+fmbTMGMsNAoA/+4G0= +github.com/VictoriaMetrics/fastcache v1.13.0/go.mod h1:hHXhl4DA2fTL2HTZDJFXWgW0LNjo6B+4aj2Wmng3TjU= github.com/allegro/bigcache v1.2.1-0.20190218064605-e24eb225f156 h1:eMwmnE/GDgah4HI848JfFxHt+iPb26b4zyfspmqY0/8= github.com/allegro/bigcache v1.2.1-0.20190218064605-e24eb225f156/go.mod h1:Cb/ax3seSYIx7SuZdm2G2xzfwmv3TPSk2ucNfQESPXM= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/bits-and-blooms/bitset v1.20.0 h1:2F+rfL86jE2d/bmw7OhqUg2Sj/1rURkBn3MdfoPyRVU= github.com/bits-and-blooms/bitset v1.20.0/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6a/7QIWpPxHddWR8= -github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cockroachdb/errors v1.11.3 h1:5bA+k2Y6r+oz/6Z/RFlNeVCesGARKuC6YymtcDrbC/I= @@ -31,7 +30,6 @@ github.com/crate-crypto/go-eth-kzg v1.4.0 h1:WzDGjHk4gFg6YzV0rJOAsTK4z3Qkz5jd4RE github.com/crate-crypto/go-eth-kzg v1.4.0/go.mod h1:J9/u5sWfznSObptgfa92Jq8rTswn6ahQWEuiLHOjCUI= github.com/crate-crypto/go-ipa v0.0.0-20240724233137-53bbb0ceb27a h1:W8mUrRp6NOVl3J+MYp5kPMoUZPp7aOYHtaua31lwRHg= github.com/crate-crypto/go-ipa v0.0.0-20240724233137-53bbb0ceb27a/go.mod h1:sTwzHBvIzm2RfVCGNEBZgRyjwK40bVoun3ZnGOCafNM= -github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/deckarep/golang-set/v2 v2.6.0 h1:XfcQbWM1LlMB8BsJ8N9vW5ehnnPVIw0je80NsVHagjM= @@ -61,9 +59,8 @@ github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= -github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= -github.com/golang/snappy v0.0.5-0.20220116011046-fa5810519dcb h1:PBC98N2aIaM3XXiurYmW7fx4GZkL8feAMVq7nEjURHk= -github.com/golang/snappy v0.0.5-0.20220116011046-fa5810519dcb/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/golang/snappy v1.0.0 h1:Oy607GVXHs7RtbggtPBnr2RmDArIsAefDwvrdWvRhGs= +github.com/golang/snappy v1.0.0/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/holiman/bloomfilter/v2 v2.0.3 h1:73e0e/V0tCydx14a0SCYS/EWCxgwLZ18CZcZKVu0fao= github.com/holiman/bloomfilter/v2 v2.0.3/go.mod h1:zpoh+gs7qcpqrHr3dB55AMiJwo0iURXE7ZOP9L9hSkA= github.com/holiman/uint256 v1.3.2 h1:a9EgMPSC1AAaj1SZL5zIQD3WbwTuHrMGOerLjGmM/TA= @@ -112,8 +109,6 @@ github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4= github.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible h1:Bn1aCHHRnjv4Bl16T8rcaFjYSrGrIZvpiGO6P3Q4GpU= github.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA= -github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/supranational/blst v0.3.16-0.20250831170142-f48500c1fdbe h1:nbdqkIGOGfUAD54q1s2YBcBz/WcsxCO9HUQ4aGV5hUw= @@ -134,7 +129,6 @@ golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.36.0 h1:KVRy2GtZBrk1cBYA7MKu5bEZFxQk4NIDV6RLVcC8o0k= golang.org/x/sys v0.36.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= golang.org/x/text v0.23.0 h1:D71I7dUrlY+VX0gQShAThNGHFxZ13dGLBHQLVl1mJlY= diff --git a/go.mod b/go.mod index 03cdf3bb2d..c91cc81d21 100644 --- a/go.mod +++ b/go.mod @@ -5,7 +5,7 @@ go 1.24.0 require ( github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.2.0 github.com/Microsoft/go-winio v0.6.2 - github.com/VictoriaMetrics/fastcache v1.12.2 + github.com/VictoriaMetrics/fastcache v1.13.0 github.com/aws/aws-sdk-go-v2 v1.21.2 github.com/aws/aws-sdk-go-v2/config v1.18.45 github.com/aws/aws-sdk-go-v2/credentials v1.13.43 @@ -31,7 +31,7 @@ require ( github.com/gballet/go-libpcsclite v0.0.0-20190607065134-2772fd86a8ff github.com/gofrs/flock v0.12.1 github.com/golang-jwt/jwt/v4 v4.5.2 - github.com/golang/snappy v0.0.5-0.20220116011046-fa5810519dcb + github.com/golang/snappy v1.0.0 github.com/google/gofuzz v1.2.0 github.com/google/uuid v1.3.0 github.com/gorilla/websocket v1.4.2 diff --git a/go.sum b/go.sum index 764cfdb668..779bcde846 100644 --- a/go.sum +++ b/go.sum @@ -16,8 +16,8 @@ github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERo github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU= github.com/StackExchange/wmi v1.2.1 h1:VIkavFPXSjcnS+O8yTq7NI32k0R5Aj+v39y29VYDOSA= github.com/StackExchange/wmi v1.2.1/go.mod h1:rcmrprowKIVzvc+NUiLncP2uuArMWLCbu9SBzvHz7e8= -github.com/VictoriaMetrics/fastcache v1.12.2 h1:N0y9ASrJ0F6h0QaC3o6uJb3NIZ9VKLjCM7NQbSmF7WI= -github.com/VictoriaMetrics/fastcache v1.12.2/go.mod h1:AmC+Nzz1+3G2eCPapF6UcsnkThDcMsQicp4xDukwJYI= +github.com/VictoriaMetrics/fastcache v1.13.0 h1:AW4mheMR5Vd9FkAPUv+NH6Nhw+fmbTMGMsNAoA/+4G0= +github.com/VictoriaMetrics/fastcache v1.13.0/go.mod h1:hHXhl4DA2fTL2HTZDJFXWgW0LNjo6B+4aj2Wmng3TjU= github.com/allegro/bigcache v1.2.1-0.20190218064605-e24eb225f156 h1:eMwmnE/GDgah4HI848JfFxHt+iPb26b4zyfspmqY0/8= github.com/allegro/bigcache v1.2.1-0.20190218064605-e24eb225f156/go.mod h1:Cb/ax3seSYIx7SuZdm2G2xzfwmv3TPSk2ucNfQESPXM= github.com/aws/aws-sdk-go-v2 v1.21.2 h1:+LXZ0sgo8quN9UOKXXzAWRT3FWd4NxeXWOZom9pE7GA= @@ -52,7 +52,6 @@ github.com/bits-and-blooms/bitset v1.20.0 h1:2F+rfL86jE2d/bmw7OhqUg2Sj/1rURkBn3M github.com/bits-and-blooms/bitset v1.20.0/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6a/7QIWpPxHddWR8= github.com/cespare/cp v0.1.0 h1:SE+dxFebS7Iik5LK0tsi1k9ZCxEaFX4AjQmoyA+1dJk= github.com/cespare/cp v0.1.0/go.mod h1:SOGHArjBr4JWaSDEVpWpo/hNg6RoKrls6Oh40hiwW+s= -github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/chzyer/logex v1.2.0/go.mod h1:9+9sk7u7pGNWYMkh0hdiL++6OeibzJccyQU4p4MedaY= @@ -165,8 +164,8 @@ github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= -github.com/golang/snappy v0.0.5-0.20220116011046-fa5810519dcb h1:PBC98N2aIaM3XXiurYmW7fx4GZkL8feAMVq7nEjURHk= -github.com/golang/snappy v0.0.5-0.20220116011046-fa5810519dcb/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/golang/snappy v1.0.0 h1:Oy607GVXHs7RtbggtPBnr2RmDArIsAefDwvrdWvRhGs= +github.com/golang/snappy v1.0.0/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golangci/lint-1 v0.0.0-20181222135242-d2cdd8c08219/go.mod h1:/X8TswGSh1pIozq4ZwCfxS0WA5JGXguxk94ar/4c87Y= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= @@ -450,7 +449,6 @@ golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.36.0 h1:KVRy2GtZBrk1cBYA7MKu5bEZFxQk4NIDV6RLVcC8o0k= golang.org/x/sys v0.36.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= From 9986270fbf78d4c3ccf03c602168f3427fc96cd4 Mon Sep 17 00:00:00 2001 From: Yuan-Yao Sung Date: Tue, 30 Sep 2025 19:30:10 +0800 Subject: [PATCH 02/23] eth/catalyst: extend payloadVersion support to osaka/post-osaka forks (#32800) This PR updates the `payloadVersion` function in `simulated_beacon.go` to handle additional following forks used during development and testing phases after Osaka. This change ensures that the simulated beacon correctly resolves the payload version for these forks, enabling consistent and valid execution payload handling during local testing or simulation. --- eth/catalyst/simulated_beacon.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/eth/catalyst/simulated_beacon.go b/eth/catalyst/simulated_beacon.go index 0642d6a1ad..c10990c233 100644 --- a/eth/catalyst/simulated_beacon.go +++ b/eth/catalyst/simulated_beacon.go @@ -100,7 +100,7 @@ type SimulatedBeacon struct { func payloadVersion(config *params.ChainConfig, time uint64) engine.PayloadVersion { switch config.LatestFork(time) { - case forks.Prague, forks.Cancun: + case forks.BPO5, forks.BPO4, forks.BPO3, forks.BPO2, forks.BPO1, forks.Osaka, forks.Prague, forks.Cancun: return engine.PayloadV3 case forks.Paris, forks.Shanghai: return engine.PayloadV2 From f9756bb8857706e64fdaf709a092ac1acc7b45e9 Mon Sep 17 00:00:00 2001 From: Zach Brown Date: Tue, 30 Sep 2025 19:30:47 +0800 Subject: [PATCH 03/23] p2p: fix error message in test (#32804) --- p2p/enode/iter_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/p2p/enode/iter_test.go b/p2p/enode/iter_test.go index 577f9c2825..922e1cde19 100644 --- a/p2p/enode/iter_test.go +++ b/p2p/enode/iter_test.go @@ -45,7 +45,7 @@ func TestReadNodesCycle(t *testing.T) { nodes := ReadNodes(iter, 10) checkNodes(t, nodes, 3) if iter.count != 10 { - t.Fatalf("%d calls to Next, want %d", iter.count, 100) + t.Fatalf("%d calls to Next, want %d", iter.count, 10) } } From bb00d26bbe6bdee45d8d0fe231a326e345d53a68 Mon Sep 17 00:00:00 2001 From: Zach Brown Date: Tue, 30 Sep 2025 19:31:42 +0800 Subject: [PATCH 04/23] signer/core: fix error message in test (#32807) --- signer/core/api_test.go | 2 +- signer/core/signed_data_test.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/signer/core/api_test.go b/signer/core/api_test.go index 0e16a1b7fd..ed4fdc5096 100644 --- a/signer/core/api_test.go +++ b/signer/core/api_test.go @@ -264,7 +264,7 @@ func TestSignTx(t *testing.T) { t.Errorf("Expected nil-response, got %v", res) } if err != keystore.ErrDecrypt { - t.Errorf("Expected ErrLocked! %v", err) + t.Errorf("Expected ErrDecrypt! %v", err) } control.approveCh <- "No way" res, err = api.SignTransaction(t.Context(), tx, &methodSig) diff --git a/signer/core/signed_data_test.go b/signer/core/signed_data_test.go index 001f6b6838..8455aaf9c5 100644 --- a/signer/core/signed_data_test.go +++ b/signer/core/signed_data_test.go @@ -202,7 +202,7 @@ func TestSignData(t *testing.T) { t.Errorf("Expected nil-data, got %x", signature) } if err != keystore.ErrDecrypt { - t.Errorf("Expected ErrLocked! '%v'", err) + t.Errorf("Expected ErrDecrypt! '%v'", err) } control.approveCh <- "No way" signature, err = api.SignData(context.Background(), apitypes.TextPlain.Mime, a, hexutil.Encode([]byte("EHLO world"))) From 1487a8577d1566497e161a04f8cee3204d4b3d36 Mon Sep 17 00:00:00 2001 From: Zach Brown Date: Tue, 30 Sep 2025 19:33:36 +0800 Subject: [PATCH 05/23] params: fix banner message (#32796) --- params/config.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/params/config.go b/params/config.go index 4e885cbdd4..e796d75535 100644 --- a/params/config.go +++ b/params/config.go @@ -624,7 +624,7 @@ func (c *ChainConfig) Description() string { } banner += fmt.Sprintf(" - Tangerine Whistle (EIP 150): #%-8v\n", c.EIP150Block) banner += fmt.Sprintf(" - Spurious Dragon/1 (EIP 155): #%-8v\n", c.EIP155Block) - banner += fmt.Sprintf(" - Spurious Dragon/2 (EIP 158): #%-8v\n", c.EIP155Block) + banner += fmt.Sprintf(" - Spurious Dragon/2 (EIP 158): #%-8v\n", c.EIP158Block) banner += fmt.Sprintf(" - Byzantium: #%-8v\n", c.ByzantiumBlock) banner += fmt.Sprintf(" - Constantinople: #%-8v\n", c.ConstantinopleBlock) banner += fmt.Sprintf(" - Petersburg: #%-8v\n", c.PetersburgBlock) From 057667151b1940e7403a97bc9fcbc207cd5b5045 Mon Sep 17 00:00:00 2001 From: Martin HS Date: Wed, 1 Oct 2025 10:05:49 +0200 Subject: [PATCH 06/23] core/types, trie: reduce allocations in derivesha (#30747) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Alternative to #30746, potential follow-up to #30743 . This PR makes the stacktrie always copy incoming value buffers, and reuse them internally. Improvement in #30743: ``` goos: linux goarch: amd64 pkg: github.com/ethereum/go-ethereum/core/types cpu: 12th Gen Intel(R) Core(TM) i7-1270P │ derivesha.1 │ derivesha.2 │ │ sec/op │ sec/op vs base │ DeriveSha200/stack_trie-8 477.8µ ± 2% 430.0µ ± 12% -10.00% (p=0.000 n=10) │ derivesha.1 │ derivesha.2 │ │ B/op │ B/op vs base │ DeriveSha200/stack_trie-8 45.17Ki ± 0% 25.65Ki ± 0% -43.21% (p=0.000 n=10) │ derivesha.1 │ derivesha.2 │ │ allocs/op │ allocs/op vs base │ DeriveSha200/stack_trie-8 1259.0 ± 0% 232.0 ± 0% -81.57% (p=0.000 n=10) ``` This PR further enhances that: ``` goos: linux goarch: amd64 pkg: github.com/ethereum/go-ethereum/core/types cpu: 12th Gen Intel(R) Core(TM) i7-1270P │ derivesha.2 │ derivesha.3 │ │ sec/op │ sec/op vs base │ DeriveSha200/stack_trie-8 430.0µ ± 12% 423.6µ ± 13% ~ (p=0.739 n=10) │ derivesha.2 │ derivesha.3 │ │ B/op │ B/op vs base │ DeriveSha200/stack_trie-8 25.654Ki ± 0% 4.960Ki ± 0% -80.67% (p=0.000 n=10) │ derivesha.2 │ derivesha.3 │ │ allocs/op │ allocs/op vs base │ DeriveSha200/stack_trie-8 232.00 ± 0% 37.00 ± 0% -84.05% (p=0.000 n=10) ``` So the total derivesha-improvement over *both PRS* is: ``` goos: linux goarch: amd64 pkg: github.com/ethereum/go-ethereum/core/types cpu: 12th Gen Intel(R) Core(TM) i7-1270P │ derivesha.1 │ derivesha.3 │ │ sec/op │ sec/op vs base │ DeriveSha200/stack_trie-8 477.8µ ± 2% 423.6µ ± 13% -11.33% (p=0.015 n=10) │ derivesha.1 │ derivesha.3 │ │ B/op │ B/op vs base │ DeriveSha200/stack_trie-8 45.171Ki ± 0% 4.960Ki ± 0% -89.02% (p=0.000 n=10) │ derivesha.1 │ derivesha.3 │ │ allocs/op │ allocs/op vs base │ DeriveSha200/stack_trie-8 1259.00 ± 0% 37.00 ± 0% -97.06% (p=0.000 n=10) ``` Since this PR always copies the incoming value, it adds a little bit of a penalty on the previous insert-benchmark, which copied nothing (always passed the same empty slice as input) : ``` goos: linux goarch: amd64 pkg: github.com/ethereum/go-ethereum/trie cpu: 12th Gen Intel(R) Core(TM) i7-1270P │ stacktrie.7 │ stacktrie.10 │ │ sec/op │ sec/op vs base │ Insert100K-8 88.21m ± 34% 92.37m ± 31% ~ (p=0.280 n=10) │ stacktrie.7 │ stacktrie.10 │ │ B/op │ B/op vs base │ Insert100K-8 3.424Ki ± 3% 4.581Ki ± 3% +33.80% (p=0.000 n=10) │ stacktrie.7 │ stacktrie.10 │ │ allocs/op │ allocs/op vs base │ Insert100K-8 22.00 ± 5% 26.00 ± 4% +18.18% (p=0.000 n=10) ``` --------- Co-authored-by: Gary Rong Co-authored-by: Felix Lange --- core/types/block.go | 2 +- core/types/hashing.go | 27 ++++++++----- core/types/hashing_test.go | 39 ++++++++++++------ internal/blocktest/test_hash.go | 5 ++- trie/bytepool.go | 51 ++++++++++++++++++++---- trie/list_hasher.go | 56 ++++++++++++++++++++++++++ trie/stacktrie.go | 70 +++++++++++++++++++-------------- trie/trie.go | 4 +- 8 files changed, 189 insertions(+), 65 deletions(-) create mode 100644 trie/list_hasher.go diff --git a/core/types/block.go b/core/types/block.go index da9614793a..b5b6468a13 100644 --- a/core/types/block.go +++ b/core/types/block.go @@ -240,7 +240,7 @@ type extblock struct { // // The receipt's bloom must already calculated for the block's bloom to be // correctly calculated. -func NewBlock(header *Header, body *Body, receipts []*Receipt, hasher TrieHasher) *Block { +func NewBlock(header *Header, body *Body, receipts []*Receipt, hasher ListHasher) *Block { if body == nil { body = &Body{} } diff --git a/core/types/hashing.go b/core/types/hashing.go index 3cc22d50d1..98fe64e15a 100644 --- a/core/types/hashing.go +++ b/core/types/hashing.go @@ -27,7 +27,7 @@ import ( "github.com/ethereum/go-ethereum/rlp" ) -// hasherPool holds LegacyKeccak256 hashers for rlpHash. +// hasherPool holds LegacyKeccak256 buffer for rlpHash. var hasherPool = sync.Pool{ New: func() interface{} { return crypto.NewKeccakState() }, } @@ -75,11 +75,17 @@ func prefixedRlpHash(prefix byte, x interface{}) (h common.Hash) { return h } -// TrieHasher is the tool used to calculate the hash of derivable list. -// This is internal, do not use. -type TrieHasher interface { +// ListHasher defines the interface for computing the hash of a derivable list. +type ListHasher interface { + // Reset clears the internal state of the hasher, preparing it for reuse. Reset() - Update([]byte, []byte) error + + // Update inserts the given key-value pair into the hasher. + // The implementation must copy the provided slices, allowing the caller + // to safely modify them after the call returns. + Update(key []byte, value []byte) error + + // Hash computes and returns the final hash of all inserted key-value pairs. Hash() common.Hash } @@ -91,19 +97,20 @@ type DerivableList interface { EncodeIndex(int, *bytes.Buffer) } +// encodeForDerive encodes the element in the list at the position i into the buffer. func encodeForDerive(list DerivableList, i int, buf *bytes.Buffer) []byte { buf.Reset() list.EncodeIndex(i, buf) - // It's really unfortunate that we need to perform this copy. - // StackTrie holds onto the values until Hash is called, so the values - // written to it must not alias. - return common.CopyBytes(buf.Bytes()) + return buf.Bytes() } // DeriveSha creates the tree hashes of transactions, receipts, and withdrawals in a block header. -func DeriveSha(list DerivableList, hasher TrieHasher) common.Hash { +func DeriveSha(list DerivableList, hasher ListHasher) common.Hash { hasher.Reset() + // Allocate a buffer for value encoding. As the hasher is claimed that all + // supplied key value pairs will be copied by hasher and safe to reuse the + // encoding buffer. valueBuf := encodeBufferPool.Get().(*bytes.Buffer) defer encodeBufferPool.Put(valueBuf) diff --git a/core/types/hashing_test.go b/core/types/hashing_test.go index 54adbc73e8..a7153bf09a 100644 --- a/core/types/hashing_test.go +++ b/core/types/hashing_test.go @@ -26,12 +26,10 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" - "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/trie" - "github.com/ethereum/go-ethereum/triedb" ) func TestDeriveSha(t *testing.T) { @@ -40,7 +38,7 @@ func TestDeriveSha(t *testing.T) { t.Fatal(err) } for len(txs) < 1000 { - exp := types.DeriveSha(txs, trie.NewEmpty(triedb.NewDatabase(rawdb.NewMemoryDatabase(), nil))) + exp := types.DeriveSha(txs, trie.NewListHasher()) got := types.DeriveSha(txs, trie.NewStackTrie(nil)) if !bytes.Equal(got[:], exp[:]) { t.Fatalf("%d txs: got %x exp %x", len(txs), got, exp) @@ -76,30 +74,45 @@ func TestEIP2718DeriveSha(t *testing.T) { } } +// goos: darwin +// goarch: arm64 +// pkg: github.com/ethereum/go-ethereum/core/types +// cpu: Apple M1 Pro +// BenchmarkDeriveSha200 +// BenchmarkDeriveSha200/std_trie +// BenchmarkDeriveSha200/std_trie-8 6754 174074 ns/op 80054 B/op 1926 allocs/op +// BenchmarkDeriveSha200/stack_trie +// BenchmarkDeriveSha200/stack_trie-8 7296 162675 ns/op 745 B/op 19 allocs/op func BenchmarkDeriveSha200(b *testing.B) { txs, err := genTxs(200) if err != nil { b.Fatal(err) } - var exp common.Hash - var got common.Hash + want := types.DeriveSha(txs, trie.NewListHasher()) + b.Run("std_trie", func(b *testing.B) { b.ReportAllocs() + var have common.Hash for b.Loop() { - exp = types.DeriveSha(txs, trie.NewEmpty(triedb.NewDatabase(rawdb.NewMemoryDatabase(), nil))) + have = types.DeriveSha(txs, trie.NewListHasher()) + } + if have != want { + b.Errorf("have %x want %x", have, want) } }) + st := trie.NewStackTrie(nil) b.Run("stack_trie", func(b *testing.B) { - b.ResetTimer() b.ReportAllocs() + var have common.Hash for b.Loop() { - got = types.DeriveSha(txs, trie.NewStackTrie(nil)) + st.Reset() + have = types.DeriveSha(txs, st) + } + if have != want { + b.Errorf("have %x want %x", have, want) } }) - if got != exp { - b.Errorf("got %x exp %x", got, exp) - } } func TestFuzzDeriveSha(t *testing.T) { @@ -107,7 +120,7 @@ func TestFuzzDeriveSha(t *testing.T) { rndSeed := mrand.Int() for i := 0; i < 10; i++ { seed := rndSeed + i - exp := types.DeriveSha(newDummy(i), trie.NewEmpty(triedb.NewDatabase(rawdb.NewMemoryDatabase(), nil))) + exp := types.DeriveSha(newDummy(i), trie.NewListHasher()) got := types.DeriveSha(newDummy(i), trie.NewStackTrie(nil)) if !bytes.Equal(got[:], exp[:]) { printList(t, newDummy(seed)) @@ -135,7 +148,7 @@ func TestDerivableList(t *testing.T) { }, } for i, tc := range tcs[1:] { - exp := types.DeriveSha(flatList(tc), trie.NewEmpty(triedb.NewDatabase(rawdb.NewMemoryDatabase(), nil))) + exp := types.DeriveSha(flatList(tc), trie.NewListHasher()) got := types.DeriveSha(flatList(tc), trie.NewStackTrie(nil)) if !bytes.Equal(got[:], exp[:]) { t.Fatalf("case %d: got %x exp %x", i, got, exp) diff --git a/internal/blocktest/test_hash.go b/internal/blocktest/test_hash.go index 4d2b077e89..b3e7098e2b 100644 --- a/internal/blocktest/test_hash.go +++ b/internal/blocktest/test_hash.go @@ -23,6 +23,7 @@ package blocktest import ( + "bytes" "hash" "github.com/ethereum/go-ethereum/common" @@ -48,8 +49,8 @@ func (h *testHasher) Reset() { // Update updates the hash state with the given key and value. func (h *testHasher) Update(key, val []byte) error { - h.hasher.Write(key) - h.hasher.Write(val) + h.hasher.Write(bytes.Clone(key)) + h.hasher.Write(bytes.Clone(val)) return nil } diff --git a/trie/bytepool.go b/trie/bytepool.go index 4f9c5672fd..31be7ae749 100644 --- a/trie/bytepool.go +++ b/trie/bytepool.go @@ -32,8 +32,8 @@ func newBytesPool(sliceCap, nitems int) *bytesPool { } } -// Get returns a slice. Safe for concurrent use. -func (bp *bytesPool) Get() []byte { +// get returns a slice. Safe for concurrent use. +func (bp *bytesPool) get() []byte { select { case b := <-bp.c: return b @@ -42,18 +42,18 @@ func (bp *bytesPool) Get() []byte { } } -// GetWithSize returns a slice with specified byte slice size. -func (bp *bytesPool) GetWithSize(s int) []byte { - b := bp.Get() +// getWithSize returns a slice with specified byte slice size. +func (bp *bytesPool) getWithSize(s int) []byte { + b := bp.get() if cap(b) < s { return make([]byte, s) } return b[:s] } -// Put returns a slice to the pool. Safe for concurrent use. This method +// put returns a slice to the pool. Safe for concurrent use. This method // will ignore slices that are too small or too large (>3x the cap) -func (bp *bytesPool) Put(b []byte) { +func (bp *bytesPool) put(b []byte) { if c := cap(b); c < bp.w || c > 3*bp.w { return } @@ -62,3 +62,40 @@ func (bp *bytesPool) Put(b []byte) { default: } } + +// unsafeBytesPool is a pool for byte slices. It is not safe for concurrent use. +type unsafeBytesPool struct { + items [][]byte + w int +} + +// newUnsafeBytesPool creates a new unsafeBytesPool. The sliceCap sets the +// capacity of newly allocated slices, and the nitems determines how many +// items the pool will hold, at maximum. +func newUnsafeBytesPool(sliceCap, nitems int) *unsafeBytesPool { + return &unsafeBytesPool{ + items: make([][]byte, 0, nitems), + w: sliceCap, + } +} + +// Get returns a slice with pre-allocated space. +func (bp *unsafeBytesPool) get() []byte { + if len(bp.items) > 0 { + last := bp.items[len(bp.items)-1] + bp.items = bp.items[:len(bp.items)-1] + return last + } + return make([]byte, 0, bp.w) +} + +// put returns a slice to the pool. This method will ignore slices that are +// too small or too large (>3x the cap) +func (bp *unsafeBytesPool) put(b []byte) { + if c := cap(b); c < bp.w || c > 3*bp.w { + return + } + if len(bp.items) < cap(bp.items) { + bp.items = append(bp.items, b) + } +} diff --git a/trie/list_hasher.go b/trie/list_hasher.go new file mode 100644 index 0000000000..8f334f9901 --- /dev/null +++ b/trie/list_hasher.go @@ -0,0 +1,56 @@ +// Copyright 2025 The go-ethereum Authors +// This file is part of the go-ethereum library. +// +// The go-ethereum library is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// The go-ethereum library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the go-ethereum library. If not, see . + +package trie + +import ( + "bytes" + + "github.com/ethereum/go-ethereum/common" +) + +// ListHasher is a wrapper of the Merkle-Patricia-Trie, which implements +// types.ListHasher. Compared to a Trie instance, the Update method of this +// type always deep-copies its input slices. +// +// This implementation is very inefficient in terms of memory allocation, +// compared with StackTrie. It exists only for correctness comparison purposes. +type ListHasher struct { + tr *Trie +} + +// NewListHasher initializes the list hasher. +func NewListHasher() *ListHasher { + return &ListHasher{ + tr: NewEmpty(nil), + } +} + +// Reset clears the internal state prepares the ListHasher for reuse. +func (h *ListHasher) Reset() { + h.tr.reset() +} + +// Update inserts a key-value pair into the trie. +func (h *ListHasher) Update(key []byte, value []byte) error { + key, value = bytes.Clone(key), bytes.Clone(value) + return h.tr.Update(key, value) +} + +// Hash computes the root hash of all inserted key-value pairs. +func (h *ListHasher) Hash() common.Hash { + return h.tr.Hash() +} diff --git a/trie/stacktrie.go b/trie/stacktrie.go index 2b7366c3c5..18fe1eea78 100644 --- a/trie/stacktrie.go +++ b/trie/stacktrie.go @@ -28,7 +28,7 @@ import ( var ( stPool = sync.Pool{New: func() any { return new(stNode) }} bPool = newBytesPool(32, 100) - _ = types.TrieHasher((*StackTrie)(nil)) + _ = types.ListHasher((*StackTrie)(nil)) ) // OnTrieNode is a callback method invoked when a trie node is committed @@ -50,6 +50,7 @@ type StackTrie struct { onTrieNode OnTrieNode kBuf []byte // buf space used for hex-key during insertions pBuf []byte // buf space used for path during insertions + vPool *unsafeBytesPool } // NewStackTrie allocates and initializes an empty trie. The committed nodes @@ -61,6 +62,7 @@ func NewStackTrie(onTrieNode OnTrieNode) *StackTrie { onTrieNode: onTrieNode, kBuf: make([]byte, 64), pBuf: make([]byte, 64), + vPool: newUnsafeBytesPool(300, 20), } } @@ -74,6 +76,9 @@ func (t *StackTrie) grow(key []byte) { } // Update inserts a (key, value) pair into the stack trie. +// +// Note the supplied key value pair is copied and managed internally, +// they are safe to be modified after this method returns. func (t *StackTrie) Update(key, value []byte) error { if len(value) == 0 { return errors.New("trying to insert empty (deletion)") @@ -88,7 +93,14 @@ func (t *StackTrie) Update(key, value []byte) error { } else { t.last = append(t.last[:0], k...) // reuse key slice } - t.insert(t.root, k, value, t.pBuf[:0]) + vBuf := t.vPool.get() + if cap(vBuf) < len(value) { + vBuf = common.CopyBytes(value) + } else { + vBuf = vBuf[:len(value)] + copy(vBuf, value) + } + t.insert(t.root, k, vBuf, t.pBuf[:0]) return nil } @@ -108,14 +120,16 @@ func (t *StackTrie) TrieKey(key []byte) []byte { // stNode represents a node within a StackTrie type stNode struct { typ uint8 // node type (as in branch, ext, leaf) - key []byte // key chunk covered by this (leaf|ext) node - val []byte // value contained by this node if it's a leaf - children [16]*stNode // list of children (for branch and exts) + key []byte // exclusive owned key chunk covered by this (leaf|ext) node + val []byte // exclusive owned value contained by this node (leaf: value; hash: hash) + children [16]*stNode // list of children (for branch and ext) } -// newLeaf constructs a leaf node with provided node key and value. The key -// will be deep-copied in the function and safe to modify afterwards, but -// value is not. +// newLeaf constructs a leaf node with provided node key and value. +// +// The key is deep-copied within the function, so it can be safely modified +// afterwards. The value is retained directly without copying, as it is +// exclusively owned by the stackTrie. func newLeaf(key, val []byte) *stNode { st := stPool.Get().(*stNode) st.typ = leafNode @@ -146,9 +160,9 @@ const ( func (n *stNode) reset() *stNode { if n.typ == hashedNode { // On hashnodes, we 'own' the val: it is guaranteed to be not held - // by external caller. Hence, when we arrive here, we can put it back - // into the pool - bPool.Put(n.val) + // by external caller. Hence, when we arrive here, we can put it + // back into the pool + bPool.put(n.val) } n.key = n.key[:0] n.val = nil @@ -172,11 +186,6 @@ func (n *stNode) getDiffIndex(key []byte) int { } // Helper function to that inserts a (key, value) pair into the trie. -// -// - The key is not retained by this method, but always copied if needed. -// - The value is retained by this method, as long as the leaf that it represents -// remains unhashed. However: it is never modified. -// - The path is not retained by this method. func (t *StackTrie) insert(st *stNode, key, value []byte, path []byte) { switch st.typ { case branchNode: /* Branch */ @@ -235,16 +244,14 @@ func (t *StackTrie) insert(st *stNode, key, value []byte, path []byte) { } var p *stNode if diffidx == 0 { - // the break is on the first byte, so - // the current node is converted into - // a branch node. + // the break is on the first byte, so the current node + // is converted into a branch node. st.children[0] = nil - p = st st.typ = branchNode + p = st } else { - // the common prefix is at least one byte - // long, insert a new intermediate branch - // node. + // the common prefix is at least one byte long, insert + // a new intermediate branch node. st.children[0] = stPool.Get().(*stNode) st.children[0].typ = branchNode p = st.children[0] @@ -280,8 +287,8 @@ func (t *StackTrie) insert(st *stNode, key, value []byte, path []byte) { if diffidx == 0 { // Convert current leaf into a branch st.typ = branchNode - p = st st.children[0] = nil + p = st } else { // Convert current node into an ext, // and insert a child branch node. @@ -307,9 +314,7 @@ func (t *StackTrie) insert(st *stNode, key, value []byte, path []byte) { st.val = nil case emptyNode: /* Empty */ - st.typ = leafNode - st.key = append(st.key, key...) // deep-copy the key as it's volatile - st.val = value + *st = *newLeaf(key, value) case hashedNode: panic("trying to insert into hash") @@ -393,18 +398,23 @@ func (t *StackTrie) hash(st *stNode, path []byte) { st.typ = hashedNode st.key = st.key[:0] - st.val = nil // Release reference to potentially externally held slice. + // Release reference to value slice which is exclusively owned + // by stackTrie itself. + if cap(st.val) > 0 && t.vPool != nil { + t.vPool.put(st.val) + } + st.val = nil // Skip committing the non-root node if the size is smaller than 32 bytes // as tiny nodes are always embedded in their parent except root node. if len(blob) < 32 && len(path) > 0 { - st.val = bPool.GetWithSize(len(blob)) + st.val = bPool.getWithSize(len(blob)) copy(st.val, blob) return } // Write the hash to the 'val'. We allocate a new val here to not mutate // input values. - st.val = bPool.GetWithSize(32) + st.val = bPool.getWithSize(32) t.h.hashDataTo(st.val, blob) // Invoke the callback it's provided. Notably, the path and blob slices are diff --git a/trie/trie.go b/trie/trie.go index 36cc732ee8..1ef2c2f1a6 100644 --- a/trie/trie.go +++ b/trie/trie.go @@ -784,8 +784,8 @@ func (t *Trie) Witness() map[string][]byte { return t.prevalueTracer.Values() } -// Reset drops the referenced root node and cleans all internal state. -func (t *Trie) Reset() { +// reset drops the referenced root node and cleans all internal state. +func (t *Trie) reset() { t.root = nil t.owner = common.Hash{} t.unhashed = 0 From f0dc47aae393abe0bb7b084345daf9108ad8897a Mon Sep 17 00:00:00 2001 From: zzzckck <152148891+zzzckck@users.noreply.github.com> Date: Thu, 2 Oct 2025 18:43:31 +0800 Subject: [PATCH 07/23] p2p/enode: fix discovery AyncFilter deadlock on shutdown (#32572) Description: We found a occasionally node hang issue on BSC, I think Geth may also have the issue, so pick the fix patch here. The fix on BSC repo: https://github.com/bnb-chain/bsc/pull/3347 When the hang occurs, there are two routines stuck. - routine 1: AsyncFilter(...) On node start, it will run part of the DiscoveryV4 protocol, which could take considerable time, here is its hang callstack: ``` goroutine 9711 [chan receive]: // this routine was stuck on read channel: `<-f.slots` github.com/ethereum/go-ethereum/p2p/enode.AsyncFilter.func1() github.com/ethereum/go-ethereum/p2p/enode/iter.go:206 +0x125 created by github.com/ethereum/go-ethereum/p2p/enode.AsyncFilter in goroutine 1 github.com/ethereum/go-ethereum/p2p/enode/iter.go:192 +0x205 ``` - Routine 2: Node Stop It is the main routine to shutdown the process, but it got stuck when it tries to shutdown the discovery components, as it tries to drain the channel of `<-f.slots`, but the extra 1 slot will never have chance to be resumed. ``` goroutine 11796 [chan receive]: github.com/ethereum/go-ethereum/p2p/enode.(*asyncFilterIter).Close.func1() github.com/ethereum/go-ethereum/p2p/enode/iter.go:248 +0x5c sync.(*Once).doSlow(0xc032a97cb8?, 0xc032a97d18?) sync/once.go:78 +0xab sync.(*Once).Do(...) sync/once.go:69 github.com/ethereum/go-ethereum/p2p/enode.(*asyncFilterIter).Close(0xc092ff8d00?) github.com/ethereum/go-ethereum/p2p/enode/iter.go:244 +0x36 github.com/ethereum/go-ethereum/p2p/enode.(*bufferIter).Close.func1() github.com/ethereum/go-ethereum/p2p/enode/iter.go:299 +0x24 sync.(*Once).doSlow(0x11a175f?, 0x2bfe63e?) sync/once.go:78 +0xab sync.(*Once).Do(...) sync/once.go:69 github.com/ethereum/go-ethereum/p2p/enode.(*bufferIter).Close(0x30?) github.com/ethereum/go-ethereum/p2p/enode/iter.go:298 +0x36 github.com/ethereum/go-ethereum/p2p/enode.(*FairMix).Close(0xc0004bfea0) github.com/ethereum/go-ethereum/p2p/enode/iter.go:379 +0xb7 github.com/ethereum/go-ethereum/eth.(*Ethereum).Stop(0xc000997b00) github.com/ethereum/go-ethereum/eth/backend.go:960 +0x4a github.com/ethereum/go-ethereum/node.(*Node).stopServices(0xc0001362a0, {0xc012e16330, 0x1, 0xc000111410?}) github.com/ethereum/go-ethereum/node/node.go:333 +0xb3 github.com/ethereum/go-ethereum/node.(*Node).Close(0xc0001362a0) github.com/ethereum/go-ethereum/node/node.go:263 +0x167 created by github.com/ethereum/go-ethereum/cmd/utils.StartNode.func1.1 in goroutine 9729 github.com/ethereum/go-ethereum/cmd/utils/cmd.go:101 +0x78 ``` The rootcause of the hang is caused by the extra 1 slot, which was designed to make sure the routines in `AsyncFilter(...)` can be finished. This PR fixes it by making sure the extra 1 shot can always be resumed when node shutdown. --- p2p/enode/iter.go | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/p2p/enode/iter.go b/p2p/enode/iter.go index 4890321f49..265d8648de 100644 --- a/p2p/enode/iter.go +++ b/p2p/enode/iter.go @@ -178,7 +178,7 @@ type AsyncFilterFunc func(context.Context, *Node) *Node func AsyncFilter(it Iterator, check AsyncFilterFunc, workers int) Iterator { f := &asyncFilterIter{ it: ensureSourceIter(it), - slots: make(chan struct{}, workers+1), + slots: make(chan struct{}, workers+1), // extra 1 slot to make sure all the goroutines can be completed passed: make(chan iteratorItem), } for range cap(f.slots) { @@ -193,6 +193,9 @@ func AsyncFilter(it Iterator, check AsyncFilterFunc, workers int) Iterator { return case <-f.slots: } + defer func() { + f.slots <- struct{}{} // the iterator has ended + }() // read from the iterator and start checking nodes in parallel // when a node is checked, it will be sent to the passed channel // and the slot will be released @@ -201,7 +204,11 @@ func AsyncFilter(it Iterator, check AsyncFilterFunc, workers int) Iterator { nodeSource := f.it.NodeSource() // check the node async, in a separate goroutine - <-f.slots + select { + case <-ctx.Done(): + return + case <-f.slots: + } go func() { if nn := check(ctx, node); nn != nil { item := iteratorItem{nn, nodeSource} @@ -213,8 +220,6 @@ func AsyncFilter(it Iterator, check AsyncFilterFunc, workers int) Iterator { f.slots <- struct{}{} }() } - // the iterator has ended - f.slots <- struct{}{} }() return f From fc8c8c1314a0fafc56297332729c2c00372e837e Mon Sep 17 00:00:00 2001 From: hero5512 Date: Thu, 2 Oct 2025 08:34:06 -0400 Subject: [PATCH 08/23] core: refactor StateProcessor to accept ChainContext interface (#32739) This pr implements https://github.com/ethereum/go-ethereum/issues/32733 to make StateProcessor more customisable. ## Compatibility notes This introduces a breaking change to users using geth EVM as a library. The `NewStateProcessor` function now takes one parameter which has the chainConfig embedded instead of 2 parameters. --- core/blockchain.go | 2 +- core/evm.go | 9 ++------- core/state_processor.go | 28 ++++++++++++++++------------ core/stateless.go | 2 +- core/vm/runtime/runtime_test.go | 12 ++++++++++++ eth/tracers/api.go | 1 + eth/tracers/api_test.go | 4 ++++ internal/ethapi/api.go | 16 ++++++++++++++++ internal/ethapi/simulate.go | 20 ++++++++++++++++++++ tests/state_test_util.go | 3 +++ 10 files changed, 76 insertions(+), 21 deletions(-) diff --git a/core/blockchain.go b/core/blockchain.go index 30f3da3004..71eb4c45a2 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -394,7 +394,7 @@ func NewBlockChain(db ethdb.Database, genesis *Genesis, engine consensus.Engine, bc.statedb = state.NewDatabase(bc.triedb, nil) bc.validator = NewBlockValidator(chainConfig, bc) bc.prefetcher = newStatePrefetcher(chainConfig, bc.hc) - bc.processor = NewStateProcessor(chainConfig, bc.hc) + bc.processor = NewStateProcessor(bc.hc) genesisHeader := bc.GetHeaderByNumber(0) if genesisHeader == nil { diff --git a/core/evm.go b/core/evm.go index 41b4e6ac58..18d940fdd2 100644 --- a/core/evm.go +++ b/core/evm.go @@ -25,21 +25,16 @@ import ( "github.com/ethereum/go-ethereum/core/tracing" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/vm" - "github.com/ethereum/go-ethereum/params" "github.com/holiman/uint256" ) // ChainContext supports retrieving headers and consensus parameters from the // current blockchain to be used during transaction processing. type ChainContext interface { + consensus.ChainHeaderReader + // Engine retrieves the chain's consensus engine. Engine() consensus.Engine - - // GetHeader returns the header corresponding to the hash/number argument pair. - GetHeader(common.Hash, uint64) *types.Header - - // Config returns the chain's configuration. - Config() *params.ChainConfig } // NewEVMBlockContext creates a new context for use in the EVM. diff --git a/core/state_processor.go b/core/state_processor.go index 4a5e69ca6e..b66046f501 100644 --- a/core/state_processor.go +++ b/core/state_processor.go @@ -35,18 +35,21 @@ import ( // // StateProcessor implements Processor. type StateProcessor struct { - config *params.ChainConfig // Chain configuration options - chain *HeaderChain // Canonical header chain + chain ChainContext // Chain context interface } // NewStateProcessor initialises a new StateProcessor. -func NewStateProcessor(config *params.ChainConfig, chain *HeaderChain) *StateProcessor { +func NewStateProcessor(chain ChainContext) *StateProcessor { return &StateProcessor{ - config: config, - chain: chain, + chain: chain, } } +// chainConfig returns the chain configuration. +func (p *StateProcessor) chainConfig() *params.ChainConfig { + return p.chain.Config() +} + // Process processes the state changes according to the Ethereum rules by running // the transaction messages using the statedb and applying any rewards to both // the processor (coinbase) and any included uncles. @@ -56,6 +59,7 @@ func NewStateProcessor(config *params.ChainConfig, chain *HeaderChain) *StatePro // transactions failed to execute due to insufficient gas it will return an error. func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg vm.Config) (*ProcessResult, error) { var ( + config = p.chainConfig() receipts types.Receipts usedGas = new(uint64) header = block.Header() @@ -66,12 +70,12 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg ) // Mutate the block and state according to any hard-fork specs - if p.config.DAOForkSupport && p.config.DAOForkBlock != nil && p.config.DAOForkBlock.Cmp(block.Number()) == 0 { + if config.DAOForkSupport && config.DAOForkBlock != nil && config.DAOForkBlock.Cmp(block.Number()) == 0 { misc.ApplyDAOHardFork(statedb) } var ( context vm.BlockContext - signer = types.MakeSigner(p.config, header.Number, header.Time) + signer = types.MakeSigner(config, header.Number, header.Time) ) // Apply pre-execution system calls. @@ -80,12 +84,12 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg tracingStateDB = state.NewHookedState(statedb, hooks) } context = NewEVMBlockContext(header, p.chain, nil) - evm := vm.NewEVM(context, tracingStateDB, p.config, cfg) + evm := vm.NewEVM(context, tracingStateDB, config, cfg) if beaconRoot := block.BeaconRoot(); beaconRoot != nil { ProcessBeaconBlockRoot(*beaconRoot, evm) } - if p.config.IsPrague(block.Number(), block.Time()) || p.config.IsVerkle(block.Number(), block.Time()) { + if config.IsPrague(block.Number(), block.Time()) || config.IsVerkle(block.Number(), block.Time()) { ProcessParentBlockHash(block.ParentHash(), evm) } @@ -106,10 +110,10 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg } // Read requests if Prague is enabled. var requests [][]byte - if p.config.IsPrague(block.Number(), block.Time()) { + if config.IsPrague(block.Number(), block.Time()) { requests = [][]byte{} // EIP-6110 - if err := ParseDepositLogs(&requests, allLogs, p.config); err != nil { + if err := ParseDepositLogs(&requests, allLogs, config); err != nil { return nil, fmt.Errorf("failed to parse deposit logs: %w", err) } // EIP-7002 @@ -123,7 +127,7 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg } // Finalize the block, applying any consensus engine specific extras (e.g. block rewards) - p.chain.engine.Finalize(p.chain, header, tracingStateDB, block.Body()) + p.chain.Engine().Finalize(p.chain, header, tracingStateDB, block.Body()) return &ProcessResult{ Receipts: receipts, diff --git a/core/stateless.go b/core/stateless.go index d21a62b4a5..b20c909da6 100644 --- a/core/stateless.go +++ b/core/stateless.go @@ -62,7 +62,7 @@ func ExecuteStateless(config *params.ChainConfig, vmconfig vm.Config, block *typ headerCache: lru.NewCache[common.Hash, *types.Header](256), engine: beacon.New(ethash.NewFaker()), } - processor := NewStateProcessor(config, chain) + processor := NewStateProcessor(chain) validator := NewBlockValidator(config, nil) // No chain, we only validate the state, not the block // Run the stateless blocks processing and self-validate certain fields diff --git a/core/vm/runtime/runtime_test.go b/core/vm/runtime/runtime_test.go index ddd32df039..a001d81623 100644 --- a/core/vm/runtime/runtime_test.go +++ b/core/vm/runtime/runtime_test.go @@ -312,6 +312,18 @@ func (d *dummyChain) Config() *params.ChainConfig { return nil } +func (d *dummyChain) CurrentHeader() *types.Header { + return nil +} + +func (d *dummyChain) GetHeaderByNumber(n uint64) *types.Header { + return d.GetHeader(common.Hash{}, n) +} + +func (d *dummyChain) GetHeaderByHash(h common.Hash) *types.Header { + return nil +} + // TestBlockhash tests the blockhash operation. It's a bit special, since it internally // requires access to a chain reader. func TestBlockhash(t *testing.T) { diff --git a/eth/tracers/api.go b/eth/tracers/api.go index a05b7a7a4a..aebeb48463 100644 --- a/eth/tracers/api.go +++ b/eth/tracers/api.go @@ -80,6 +80,7 @@ type StateReleaseFunc func() type Backend interface { HeaderByHash(ctx context.Context, hash common.Hash) (*types.Header, error) HeaderByNumber(ctx context.Context, number rpc.BlockNumber) (*types.Header, error) + CurrentHeader() *types.Header BlockByHash(ctx context.Context, hash common.Hash) (*types.Block, error) BlockByNumber(ctx context.Context, number rpc.BlockNumber) (*types.Block, error) GetCanonicalTransaction(txHash common.Hash) (bool, *types.Transaction, common.Hash, uint64, uint64) diff --git a/eth/tracers/api_test.go b/eth/tracers/api_test.go index 39c39ff05d..4173d2a791 100644 --- a/eth/tracers/api_test.go +++ b/eth/tracers/api_test.go @@ -142,6 +142,10 @@ func (b *testBackend) ChainDb() ethdb.Database { return b.chaindb } +func (b *testBackend) CurrentHeader() *types.Header { + return b.chain.CurrentHeader() +} + // teardown releases the associated resources. func (b *testBackend) teardown() { b.chain.Stop() diff --git a/internal/ethapi/api.go b/internal/ethapi/api.go index 2432bb70b8..c3f267027c 100644 --- a/internal/ethapi/api.go +++ b/internal/ethapi/api.go @@ -636,6 +636,8 @@ func (api *BlockChainAPI) GetBlockReceipts(ctx context.Context, blockNrOrHash rp type ChainContextBackend interface { Engine() consensus.Engine HeaderByNumber(context.Context, rpc.BlockNumber) (*types.Header, error) + HeaderByHash(context.Context, common.Hash) (*types.Header, error) + CurrentHeader() *types.Header ChainConfig() *params.ChainConfig } @@ -669,6 +671,20 @@ func (context *ChainContext) Config() *params.ChainConfig { return context.b.ChainConfig() } +func (context *ChainContext) CurrentHeader() *types.Header { + return context.b.CurrentHeader() +} + +func (context *ChainContext) GetHeaderByNumber(number uint64) *types.Header { + header, _ := context.b.HeaderByNumber(context.ctx, rpc.BlockNumber(number)) + return header +} + +func (context *ChainContext) GetHeaderByHash(hash common.Hash) *types.Header { + header, _ := context.b.HeaderByHash(context.ctx, hash) + return header +} + func doCall(ctx context.Context, b Backend, args TransactionArgs, state *state.StateDB, header *types.Header, overrides *override.StateOverride, blockOverrides *override.BlockOverrides, timeout time.Duration, globalGasCap uint64) (*core.ExecutionResult, error) { blockCtx := core.NewEVMBlockContext(header, NewChainContext(ctx, b), nil) if blockOverrides != nil { diff --git a/internal/ethapi/simulate.go b/internal/ethapi/simulate.go index 75b5c5ffa8..2bda69b315 100644 --- a/internal/ethapi/simulate.go +++ b/internal/ethapi/simulate.go @@ -541,3 +541,23 @@ func (b *simBackend) HeaderByNumber(ctx context.Context, number rpc.BlockNumber) func (b *simBackend) ChainConfig() *params.ChainConfig { return b.b.ChainConfig() } + +func (b *simBackend) HeaderByHash(ctx context.Context, hash common.Hash) (*types.Header, error) { + if b.base.Hash() == hash { + return b.base, nil + } + if header, err := b.b.HeaderByHash(ctx, hash); err == nil { + return header, nil + } + // Check simulated headers + for _, header := range b.headers { + if header.Hash() == hash { + return header, nil + } + } + return nil, errors.New("header not found") +} + +func (b *simBackend) CurrentHeader() *types.Header { + return b.b.CurrentHeader() +} diff --git a/tests/state_test_util.go b/tests/state_test_util.go index b8d3c4fb92..1d6cc8db70 100644 --- a/tests/state_test_util.go +++ b/tests/state_test_util.go @@ -559,3 +559,6 @@ type dummyChain struct { func (d *dummyChain) Engine() consensus.Engine { return nil } func (d *dummyChain) GetHeader(h common.Hash, n uint64) *types.Header { return nil } func (d *dummyChain) Config() *params.ChainConfig { return d.config } +func (d *dummyChain) CurrentHeader() *types.Header { return nil } +func (d *dummyChain) GetHeaderByNumber(n uint64) *types.Header { return nil } +func (d *dummyChain) GetHeaderByHash(h common.Hash) *types.Header { return nil } From 4927e89647a0d27f284472aa563890035d3662db Mon Sep 17 00:00:00 2001 From: Csaba Kiraly Date: Thu, 2 Oct 2025 17:27:35 +0200 Subject: [PATCH 09/23] p2p/enode: fix asyncfilter comment (#32823) just finisher the sentence Signed-off-by: Csaba Kiraly --- p2p/enode/iter.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/p2p/enode/iter.go b/p2p/enode/iter.go index 265d8648de..54c2fc7258 100644 --- a/p2p/enode/iter.go +++ b/p2p/enode/iter.go @@ -174,7 +174,8 @@ type AsyncFilterFunc func(context.Context, *Node) *Node // AsyncFilter creates an iterator which checks nodes in parallel. // The 'check' function is called on multiple goroutines to filter each node // from the upstream iterator. When check returns nil, the node will be skipped. -// It can also return a new node to be returned by the iterator instead of the . +// It can also return a new node to be returned by the iterator instead of the +// original one. func AsyncFilter(it Iterator, check AsyncFilterFunc, workers int) Iterator { f := &asyncFilterIter{ it: ensureSourceIter(it), From 1e4b39ed122f475ac3f776ae66c8d065e845a84e Mon Sep 17 00:00:00 2001 From: hero5512 Date: Thu, 2 Oct 2025 11:32:20 -0400 Subject: [PATCH 10/23] trie: cleaner array concatenation (#32756) It uses the slices.Concat and slices.Clone methods available now in Go. --- trie/sync.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/trie/sync.go b/trie/sync.go index 8d0ce6901c..404d67f154 100644 --- a/trie/sync.go +++ b/trie/sync.go @@ -19,6 +19,7 @@ package trie import ( "errors" "fmt" + "slices" "sync" "github.com/ethereum/go-ethereum/common" @@ -553,7 +554,7 @@ func (s *Sync) children(req *nodeRequest, object node) ([]*nodeRequest, error) { } children = []childNode{{ node: node.Val, - path: append(append([]byte(nil), req.path...), key...), + path: slices.Concat(req.path, key), }} // Mark all internal nodes between shortNode and its **in disk** // child as invalid. This is essential in the case of path mode @@ -595,7 +596,7 @@ func (s *Sync) children(req *nodeRequest, object node) ([]*nodeRequest, error) { if node.Children[i] != nil { children = append(children, childNode{ node: node.Children[i], - path: append(append([]byte(nil), req.path...), byte(i)), + path: append(slices.Clone(req.path), byte(i)), }) } } From 477ee5873ba9fde828c7964fcb9f881799c9d6c2 Mon Sep 17 00:00:00 2001 From: Nikita Mescheryakov Date: Mon, 6 Oct 2025 21:19:25 +0500 Subject: [PATCH 11/23] internal/ethapi: add timestamp to logs in eth_simulate (#32831) Adds blockTimestamp to the logs in response of eth_simulateV1. --------- Co-authored-by: Sina Mahmoodi --- internal/ethapi/api_test.go | 30 +++++++++++++++++------------- internal/ethapi/logtracer.go | 21 ++++++++++++--------- internal/ethapi/simulate.go | 2 +- 3 files changed, 30 insertions(+), 23 deletions(-) diff --git a/internal/ethapi/api_test.go b/internal/ethapi/api_test.go index 2e0b1c3bc0..d3278c04e7 100644 --- a/internal/ethapi/api_test.go +++ b/internal/ethapi/api_test.go @@ -1327,10 +1327,11 @@ func TestSimulateV1(t *testing.T) { validation = true ) type log struct { - Address common.Address `json:"address"` - Topics []common.Hash `json:"topics"` - Data hexutil.Bytes `json:"data"` - BlockNumber hexutil.Uint64 `json:"blockNumber"` + Address common.Address `json:"address"` + Topics []common.Hash `json:"topics"` + Data hexutil.Bytes `json:"data"` + BlockNumber hexutil.Uint64 `json:"blockNumber"` + BlockTimestamp hexutil.Uint64 `json:"blockTimestamp"` // Skip txHash //TxHash common.Hash `json:"transactionHash" gencodec:"required"` TxIndex hexutil.Uint `json:"transactionIndex"` @@ -1677,10 +1678,11 @@ func TestSimulateV1(t *testing.T) { Calls: []callRes{{ ReturnValue: "0x", Logs: []log{{ - Address: randomAccounts[2].addr, - Topics: []common.Hash{common.HexToHash("0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff")}, - BlockNumber: hexutil.Uint64(11), - Data: hexutil.Bytes{}, + Address: randomAccounts[2].addr, + Topics: []common.Hash{common.HexToHash("0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff")}, + BlockNumber: hexutil.Uint64(11), + BlockTimestamp: hexutil.Uint64(0x70), + Data: hexutil.Bytes{}, }}, GasUsed: "0x5508", Status: "0x1", @@ -1853,8 +1855,9 @@ func TestSimulateV1(t *testing.T) { addressToHash(accounts[0].addr), addressToHash(randomAccounts[0].addr), }, - Data: hexutil.Bytes(common.BigToHash(big.NewInt(50)).Bytes()), - BlockNumber: hexutil.Uint64(11), + Data: hexutil.Bytes(common.BigToHash(big.NewInt(50)).Bytes()), + BlockNumber: hexutil.Uint64(11), + BlockTimestamp: hexutil.Uint64(0x70), }, { Address: transferAddress, Topics: []common.Hash{ @@ -1862,9 +1865,10 @@ func TestSimulateV1(t *testing.T) { addressToHash(randomAccounts[0].addr), addressToHash(fixedAccount.addr), }, - Data: hexutil.Bytes(common.BigToHash(big.NewInt(100)).Bytes()), - BlockNumber: hexutil.Uint64(11), - Index: hexutil.Uint(1), + Data: hexutil.Bytes(common.BigToHash(big.NewInt(100)).Bytes()), + BlockNumber: hexutil.Uint64(11), + BlockTimestamp: hexutil.Uint64(0x70), + Index: hexutil.Uint(1), }}, Status: "0x1", }}, diff --git a/internal/ethapi/logtracer.go b/internal/ethapi/logtracer.go index 456aa93736..54d2d653ea 100644 --- a/internal/ethapi/logtracer.go +++ b/internal/ethapi/logtracer.go @@ -53,15 +53,17 @@ type tracer struct { count int traceTransfers bool blockNumber uint64 + blockTimestamp uint64 blockHash common.Hash txHash common.Hash txIdx uint } -func newTracer(traceTransfers bool, blockNumber uint64, blockHash, txHash common.Hash, txIndex uint) *tracer { +func newTracer(traceTransfers bool, blockNumber uint64, blockTimestamp uint64, blockHash, txHash common.Hash, txIndex uint) *tracer { return &tracer{ traceTransfers: traceTransfers, blockNumber: blockNumber, + blockTimestamp: blockTimestamp, blockHash: blockHash, txHash: txHash, txIdx: txIndex, @@ -115,14 +117,15 @@ func (t *tracer) onLog(log *types.Log) { func (t *tracer) captureLog(address common.Address, topics []common.Hash, data []byte) { t.logs[len(t.logs)-1] = append(t.logs[len(t.logs)-1], &types.Log{ - Address: address, - Topics: topics, - Data: data, - BlockNumber: t.blockNumber, - BlockHash: t.blockHash, - TxHash: t.txHash, - TxIndex: t.txIdx, - Index: uint(t.count), + Address: address, + Topics: topics, + Data: data, + BlockNumber: t.blockNumber, + BlockTimestamp: t.blockTimestamp, + BlockHash: t.blockHash, + TxHash: t.txHash, + TxIndex: t.txIdx, + Index: uint(t.count), }) t.count++ } diff --git a/internal/ethapi/simulate.go b/internal/ethapi/simulate.go index 2bda69b315..0d1a59b371 100644 --- a/internal/ethapi/simulate.go +++ b/internal/ethapi/simulate.go @@ -244,7 +244,7 @@ func (sim *simulator) processBlock(ctx context.Context, block *simBlock, header, callResults = make([]simCallResult, len(block.Calls)) receipts = make([]*types.Receipt, len(block.Calls)) // Block hash will be repaired after execution. - tracer = newTracer(sim.traceTransfers, blockContext.BlockNumber.Uint64(), common.Hash{}, common.Hash{}, 0) + tracer = newTracer(sim.traceTransfers, blockContext.BlockNumber.Uint64(), blockContext.Time, common.Hash{}, common.Hash{}, 0) vmConfig = &vm.Config{ NoBaseFee: !sim.validate, Tracer: tracer.Hooks(), From ee309827c680d4efc8f9cebf82017bdbec6be051 Mon Sep 17 00:00:00 2001 From: Sina M <1591639+s1na@users.noreply.github.com> Date: Tue, 7 Oct 2025 11:24:30 +0200 Subject: [PATCH 12/23] build: faster gh actions workflow, no ubuntu on appveyor (#32829) This PR does a few things: - Sets the gh actions runner sizes for lint (s) and test (l) workflows - Runs the tests on gh actions in parallel - Skips fetching the spec tests when unnecessary (on windows in appveyor) - Removes ubuntu appveyor runner since it's essentially duplicate of the gh action workflow now The gh test seems to go down from ~35min to ~13min. --- .github/workflows/go.yml | 6 +++--- appveyor.yml | 22 +--------------------- build/ci.go | 28 +++++++++++++++++----------- 3 files changed, 21 insertions(+), 35 deletions(-) diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml index cc8ea36d74..b8cf7f75e0 100644 --- a/.github/workflows/go.yml +++ b/.github/workflows/go.yml @@ -10,7 +10,7 @@ on: jobs: lint: name: Lint - runs-on: self-hosted-ghr + runs-on: [self-hosted-ghr, size-s-x64] steps: - uses: actions/checkout@v4 with: @@ -37,7 +37,7 @@ jobs: test: name: Test needs: lint - runs-on: self-hosted-ghr + runs-on: [self-hosted-ghr, size-l-x64] strategy: matrix: go: @@ -55,4 +55,4 @@ jobs: cache: false - name: Run tests - run: go run build/ci.go test + run: go run build/ci.go test -p 8 diff --git a/appveyor.yml b/appveyor.yml index ae1c74c18e..8dce7f30a2 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -2,7 +2,6 @@ clone_depth: 5 version: "{branch}.{build}" image: - - Ubuntu - Visual Studio 2019 environment: @@ -17,25 +16,6 @@ install: - go version for: - # Linux has its own script without -arch and -cc. - # The linux builder also runs lint. - - matrix: - only: - - image: Ubuntu - build_script: - - go run build/ci.go lint - - go run build/ci.go check_generate - - go run build/ci.go check_baddeps - - go run build/ci.go install -dlgo - test_script: - - go run build/ci.go test -dlgo -short - - # linux/386 is disabled. - - matrix: - exclude: - - image: Ubuntu - GETH_ARCH: 386 - # Windows builds for amd64 + 386. - matrix: only: @@ -56,4 +36,4 @@ for: - go run build/ci.go archive -arch %GETH_ARCH% -type zip -signer WINDOWS_SIGNING_KEY -upload gethstore/builds - go run build/ci.go nsis -arch %GETH_ARCH% -signer WINDOWS_SIGNING_KEY -upload gethstore/builds test_script: - - go run build/ci.go test -dlgo -arch %GETH_ARCH% -cc %GETH_CC% -short + - go run build/ci.go test -dlgo -arch %GETH_ARCH% -cc %GETH_CC% -short -skip-spectests diff --git a/build/ci.go b/build/ci.go index da867a1516..905f6e4072 100644 --- a/build/ci.go +++ b/build/ci.go @@ -281,20 +281,26 @@ func buildFlags(env build.Environment, staticLinking bool, buildTags []string) ( func doTest(cmdline []string) { var ( - dlgo = flag.Bool("dlgo", false, "Download Go and build with it") - arch = flag.String("arch", "", "Run tests for given architecture") - cc = flag.String("cc", "", "Sets C compiler binary") - coverage = flag.Bool("coverage", false, "Whether to record code coverage") - verbose = flag.Bool("v", false, "Whether to log verbosely") - race = flag.Bool("race", false, "Execute the race detector") - short = flag.Bool("short", false, "Pass the 'short'-flag to go test") - cachedir = flag.String("cachedir", "./build/cache", "directory for caching downloads") + dlgo = flag.Bool("dlgo", false, "Download Go and build with it") + arch = flag.String("arch", "", "Run tests for given architecture") + cc = flag.String("cc", "", "Sets C compiler binary") + coverage = flag.Bool("coverage", false, "Whether to record code coverage") + verbose = flag.Bool("v", false, "Whether to log verbosely") + race = flag.Bool("race", false, "Execute the race detector") + short = flag.Bool("short", false, "Pass the 'short'-flag to go test") + cachedir = flag.String("cachedir", "./build/cache", "directory for caching downloads") + skipspectests = flag.Bool("skip-spectests", false, "Skip downloading execution-spec-tests fixtures") + threads = flag.Int("p", 1, "Number of CPU threads to use for testing") ) flag.CommandLine.Parse(cmdline) - // Get test fixtures. + // Load checksums file (needed for both spec tests and dlgo) csdb := download.MustLoadChecksums("build/checksums.txt") - downloadSpecTestFixtures(csdb, *cachedir) + + // Get test fixtures. + if !*skipspectests { + downloadSpecTestFixtures(csdb, *cachedir) + } // Configure the toolchain. tc := build.GoToolchain{GOARCH: *arch, CC: *cc} @@ -315,7 +321,7 @@ func doTest(cmdline []string) { // Test a single package at a time. CI builders are slow // and some tests run into timeouts under load. - gotest.Args = append(gotest.Args, "-p", "1") + gotest.Args = append(gotest.Args, "-p", fmt.Sprintf("%d", *threads)) if *coverage { gotest.Args = append(gotest.Args, "-covermode=atomic", "-cover") } From d67037a981cbb6355b657d30429af3c325921364 Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Wed, 8 Oct 2025 11:14:27 +0200 Subject: [PATCH 13/23] cmd/devp2p/internal/ethtest: update to PoS-only test chain (#32850) --- cmd/devp2p/internal/ethtest/mkchain.sh | 5 +- cmd/devp2p/internal/ethtest/snap.go | 32 +- .../internal/ethtest/testdata/chain.rlp | Bin 341951 -> 451888 bytes .../internal/ethtest/testdata/forkenv.json | 37 +- .../internal/ethtest/testdata/genesis.json | 59 +- .../internal/ethtest/testdata/headblock.json | 21 +- .../internal/ethtest/testdata/headfcu.json | 8 +- .../internal/ethtest/testdata/headstate.json | 6492 +++---- .../internal/ethtest/testdata/newpayload.json | 15735 +++++++++++----- .../internal/ethtest/testdata/txinfo.json | 5390 +++--- 10 files changed, 16749 insertions(+), 11030 deletions(-) diff --git a/cmd/devp2p/internal/ethtest/mkchain.sh b/cmd/devp2p/internal/ethtest/mkchain.sh index b9253e8ca7..fab630d977 100644 --- a/cmd/devp2p/internal/ethtest/mkchain.sh +++ b/cmd/devp2p/internal/ethtest/mkchain.sh @@ -1,9 +1,10 @@ #!/bin/sh hivechain generate \ + --pos \ --fork-interval 6 \ --tx-interval 1 \ - --length 500 \ + --length 600 \ --outdir testdata \ - --lastfork cancun \ + --lastfork prague \ --outputs accounts,genesis,chain,headstate,txinfo,headblock,headfcu,newpayload,forkenv diff --git a/cmd/devp2p/internal/ethtest/snap.go b/cmd/devp2p/internal/ethtest/snap.go index 9c1efa0e8e..f4fce0931f 100644 --- a/cmd/devp2p/internal/ethtest/snap.go +++ b/cmd/devp2p/internal/ethtest/snap.go @@ -86,9 +86,9 @@ func (s *Suite) TestSnapGetAccountRange(t *utesting.T) { root: root, startingHash: zero, limitHash: ffHash, - expAccounts: 86, + expAccounts: 67, expFirst: firstKey, - expLast: common.HexToHash("0x445cb5c1278fdce2f9cbdb681bdd76c52f8e50e41dbd9e220242a69ba99ac099"), + expLast: common.HexToHash("0x622e662246601dd04f996289ce8b85e86db7bb15bb17f86487ec9d543ddb6f9a"), desc: "In this test, we request the entire state range, but limit the response to 4000 bytes.", }, { @@ -96,9 +96,9 @@ func (s *Suite) TestSnapGetAccountRange(t *utesting.T) { root: root, startingHash: zero, limitHash: ffHash, - expAccounts: 65, + expAccounts: 49, expFirst: firstKey, - expLast: common.HexToHash("0x2e6fe1362b3e388184fd7bf08e99e74170b26361624ffd1c5f646da7067b58b6"), + expLast: common.HexToHash("0x445cb5c1278fdce2f9cbdb681bdd76c52f8e50e41dbd9e220242a69ba99ac099"), desc: "In this test, we request the entire state range, but limit the response to 3000 bytes.", }, { @@ -106,9 +106,9 @@ func (s *Suite) TestSnapGetAccountRange(t *utesting.T) { root: root, startingHash: zero, limitHash: ffHash, - expAccounts: 44, + expAccounts: 34, expFirst: firstKey, - expLast: common.HexToHash("0x1c3f74249a4892081ba0634a819aec9ed25f34c7653f5719b9098487e65ab595"), + expLast: common.HexToHash("0x2ef46ebd2073cecde499c2e8df028ad79a26d57bfaa812c4c6f7eb4c9617b913"), desc: "In this test, we request the entire state range, but limit the response to 2000 bytes.", }, { @@ -177,9 +177,9 @@ The server should return the first available account.`, root: root, startingHash: firstKey, limitHash: ffHash, - expAccounts: 86, + expAccounts: 67, expFirst: firstKey, - expLast: common.HexToHash("0x445cb5c1278fdce2f9cbdb681bdd76c52f8e50e41dbd9e220242a69ba99ac099"), + expLast: common.HexToHash("0x622e662246601dd04f996289ce8b85e86db7bb15bb17f86487ec9d543ddb6f9a"), desc: `In this test, startingHash is exactly the first available account key. The server should return the first available account of the state as the first item.`, }, @@ -188,9 +188,9 @@ The server should return the first available account of the state as the first i root: root, startingHash: hashAdd(firstKey, 1), limitHash: ffHash, - expAccounts: 86, + expAccounts: 67, expFirst: secondKey, - expLast: common.HexToHash("0x4615e5f5df5b25349a00ad313c6cd0436b6c08ee5826e33a018661997f85ebaa"), + expLast: common.HexToHash("0x66192e4c757fba1cdc776e6737008f42d50370d3cd801db3624274283bf7cd63"), desc: `In this test, startingHash is after the first available key. The server should return the second account of the state as the first item.`, }, @@ -226,9 +226,9 @@ server to return no data because genesis is older than 127 blocks.`, root: s.chain.RootAt(int(s.chain.Head().Number().Uint64()) - 127), startingHash: zero, limitHash: ffHash, - expAccounts: 84, + expAccounts: 66, expFirst: firstKey, - expLast: common.HexToHash("0x580aa878e2f92d113a12c0a3ce3c21972b03dbe80786858d49a72097e2c491a3"), + expLast: common.HexToHash("0x729953a43ed6c913df957172680a17e5735143ad767bda8f58ac84ec62fbec5e"), desc: `This test requests data at a state root that is 127 blocks old. We expect the server to have this state available.`, }, @@ -657,8 +657,8 @@ The server should reject the request.`, // It's a bit unfortunate these are hard-coded, but the result depends on // a lot of aspects of the state trie and can't be guessed in a simple // way. So you'll have to update this when the test chain is changed. - common.HexToHash("0x3e963a69401a70224cbfb8c0cc2249b019041a538675d71ccf80c9328d114e2e"), - common.HexToHash("0xd0670d09cdfbf3c6320eb3e92c47c57baa6c226551a2d488c05581091e6b1689"), + common.HexToHash("0x5bdc0d6057b35642a16d27223ea5454e5a17a400e28f7328971a5f2a87773b76"), + common.HexToHash("0x0a76c9812ca90ffed8ee4d191e683f93386b6e50cfe3679c0760d27510aa7fc5"), empty, empty, empty, empty, empty, empty, empty, empty, empty, empty, empty, empty, empty, empty, empty, empty, empty, empty, empty, empty, empty, empty, empty, empty, empty, empty, empty, empty, empty, empty, empty, empty, empty, empty, empty, empty, @@ -678,8 +678,8 @@ The server should reject the request.`, // be updated when the test chain is changed. expHashes: []common.Hash{ empty, - common.HexToHash("0xd0670d09cdfbf3c6320eb3e92c47c57baa6c226551a2d488c05581091e6b1689"), - common.HexToHash("0x3e963a69401a70224cbfb8c0cc2249b019041a538675d71ccf80c9328d114e2e"), + common.HexToHash("0x0a76c9812ca90ffed8ee4d191e683f93386b6e50cfe3679c0760d27510aa7fc5"), + common.HexToHash("0x5bdc0d6057b35642a16d27223ea5454e5a17a400e28f7328971a5f2a87773b76"), }, }, diff --git a/cmd/devp2p/internal/ethtest/testdata/chain.rlp b/cmd/devp2p/internal/ethtest/testdata/chain.rlp index 2964c02bb1fb7f695fe6eb9c1c113f9db0b7c97b..7d4f4b3efe5d204312966e56040e759ce53b6600 100644 GIT binary patch literal 451888 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

9J?uR9fRSN| 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

REClOl)IIGpaOOSU*o%(ovM%%c3*qn6q4VI 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

3MfB$6A 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 PgC@ZCACEHDK6>;YypJV? literal 341951 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

BUlu*YmpL9FoEf$3g&@_?xj1~>XJ8%0Z+ETB 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 Date: Wed, 8 Oct 2025 12:29:51 +0300 Subject: [PATCH 14/23] core/rawdb: remove duplicated type storedReceiptRLP (#32820) Co-authored-by: Felix Lange --- core/rawdb/accessors_chain.go | 15 +++------------ 1 file changed, 3 insertions(+), 12 deletions(-) diff --git a/core/rawdb/accessors_chain.go b/core/rawdb/accessors_chain.go index 0782a0e7da..f20d675ff8 100644 --- a/core/rawdb/accessors_chain.go +++ b/core/rawdb/accessors_chain.go @@ -664,15 +664,6 @@ func DeleteReceipts(db ethdb.KeyValueWriter, hash common.Hash, number uint64) { } } -// storedReceiptRLP is the storage encoding of a receipt. -// Re-definition in core/types/receipt.go. -// TODO: Re-use the existing definition. -type storedReceiptRLP struct { - PostStateOrStatus []byte - CumulativeGasUsed uint64 - Logs []*types.Log -} - // ReceiptLogs is a barebone version of ReceiptForStorage which only keeps // the list of logs. When decoding a stored receipt into this object we // avoid creating the bloom filter. @@ -682,11 +673,11 @@ type receiptLogs struct { // DecodeRLP implements rlp.Decoder. func (r *receiptLogs) DecodeRLP(s *rlp.Stream) error { - var stored storedReceiptRLP - if err := s.Decode(&stored); err != nil { + var rs types.ReceiptForStorage + if err := rs.DecodeRLP(s); err != nil { return err } - r.Logs = stored.Logs + r.Logs = rs.Logs return nil } From 064ab701ea98dd4e32b331318ca7f2cc5e5edcaa Mon Sep 17 00:00:00 2001 From: Nicolas Gotchac Date: Wed, 8 Oct 2025 12:50:03 +0200 Subject: [PATCH 15/23] eth/protocols/eth: use BlockChain interface in Handshake (#32847) --- eth/protocols/eth/handshake.go | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/eth/protocols/eth/handshake.go b/eth/protocols/eth/handshake.go index 824e49fb2b..bb3d1b8eb4 100644 --- a/eth/protocols/eth/handshake.go +++ b/eth/protocols/eth/handshake.go @@ -22,7 +22,6 @@ import ( "time" "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core/forkid" "github.com/ethereum/go-ethereum/metrics" "github.com/ethereum/go-ethereum/p2p" @@ -36,7 +35,7 @@ const ( // Handshake executes the eth protocol handshake, negotiating version number, // network IDs, difficulties, head and genesis blocks. -func (p *Peer) Handshake(networkID uint64, chain *core.BlockChain, rangeMsg BlockRangeUpdatePacket) error { +func (p *Peer) Handshake(networkID uint64, chain forkid.Blockchain, rangeMsg BlockRangeUpdatePacket) error { switch p.version { case ETH69: return p.handshake69(networkID, chain, rangeMsg) @@ -47,10 +46,10 @@ func (p *Peer) Handshake(networkID uint64, chain *core.BlockChain, rangeMsg Bloc } } -func (p *Peer) handshake68(networkID uint64, chain *core.BlockChain) error { +func (p *Peer) handshake68(networkID uint64, chain forkid.Blockchain) error { var ( genesis = chain.Genesis() - latest = chain.CurrentBlock() + latest = chain.CurrentHeader() forkID = forkid.NewID(chain.Config(), genesis, latest.Number.Uint64(), latest.Time) forkFilter = forkid.NewFilter(chain) ) @@ -92,10 +91,10 @@ func (p *Peer) readStatus68(networkID uint64, status *StatusPacket68, genesis co return nil } -func (p *Peer) handshake69(networkID uint64, chain *core.BlockChain, rangeMsg BlockRangeUpdatePacket) error { +func (p *Peer) handshake69(networkID uint64, chain forkid.Blockchain, rangeMsg BlockRangeUpdatePacket) error { var ( genesis = chain.Genesis() - latest = chain.CurrentBlock() + latest = chain.CurrentHeader() forkID = forkid.NewID(chain.Config(), genesis, latest.Number.Uint64(), latest.Time) forkFilter = forkid.NewFilter(chain) ) From e42af536c552538a8ca8c353a26669fd2e9eb150 Mon Sep 17 00:00:00 2001 From: Alexey Osipov Date: Wed, 8 Oct 2025 20:23:44 +0300 Subject: [PATCH 16/23] cmd/devp2p/internal/ethtest: accept responses in any order (#32834) In both `TestSimultaneousRequests` and `TestSameRequestID`, we send two concurrent requests. The client under test is free to respond in either order, so we need to handle responses both ways. Also fixes an issue where some generated blob transactions didn't have any blobs. --------- Co-authored-by: Felix Lange --- cmd/devp2p/internal/ethtest/protocol.go | 6 ++ cmd/devp2p/internal/ethtest/suite.go | 97 +++++++++++++++---------- 2 files changed, 63 insertions(+), 40 deletions(-) diff --git a/cmd/devp2p/internal/ethtest/protocol.go b/cmd/devp2p/internal/ethtest/protocol.go index a21d1ca7a1..af76082318 100644 --- a/cmd/devp2p/internal/ethtest/protocol.go +++ b/cmd/devp2p/internal/ethtest/protocol.go @@ -86,3 +86,9 @@ func protoOffset(proto Proto) uint64 { panic("unhandled protocol") } } + +// msgTypePtr is the constraint for protocol message types. +type msgTypePtr[U any] interface { + *U + Kind() byte +} diff --git a/cmd/devp2p/internal/ethtest/suite.go b/cmd/devp2p/internal/ethtest/suite.go index 47327b6844..c23360bf82 100644 --- a/cmd/devp2p/internal/ethtest/suite.go +++ b/cmd/devp2p/internal/ethtest/suite.go @@ -196,6 +196,7 @@ to check if the node disconnects after receiving multiple invalid requests.`) func (s *Suite) TestSimultaneousRequests(t *utesting.T) { t.Log(`This test requests blocks headers from the node, performing two requests concurrently, with different request IDs.`) + conn, err := s.dialAndPeer(nil) if err != nil { t.Fatalf("peering failed: %v", err) @@ -235,37 +236,36 @@ concurrently, with different request IDs.`) } // Wait for responses. - headers1 := new(eth.BlockHeadersPacket) - if err := conn.ReadMsg(ethProto, eth.BlockHeadersMsg, &headers1); err != nil { - t.Fatalf("error reading block headers msg: %v", err) - } - if got, want := headers1.RequestId, req1.RequestId; got != want { - t.Fatalf("unexpected request id in response: got %d, want %d", got, want) - } - headers2 := new(eth.BlockHeadersPacket) - if err := conn.ReadMsg(ethProto, eth.BlockHeadersMsg, &headers2); err != nil { - t.Fatalf("error reading block headers msg: %v", err) - } - if got, want := headers2.RequestId, req2.RequestId; got != want { - t.Fatalf("unexpected request id in response: got %d, want %d", got, want) + // Note they can arrive in either order. + resp, err := collectResponses(conn, 2, func(msg *eth.BlockHeadersPacket) uint64 { + if msg.RequestId != 111 && msg.RequestId != 222 { + t.Fatalf("response with unknown request ID: %v", msg.RequestId) + } + return msg.RequestId + }) + if err != nil { + t.Fatal(err) } - // Check received headers for accuracy. + // Check if headers match. + resp1 := resp[111] if expected, err := s.chain.GetHeaders(req1); err != nil { t.Fatalf("failed to get expected headers for request 1: %v", err) - } else if !headersMatch(expected, headers1.BlockHeadersRequest) { - t.Fatalf("header mismatch: \nexpected %v \ngot %v", expected, headers1) + } else if !headersMatch(expected, resp1.BlockHeadersRequest) { + t.Fatalf("header mismatch for request ID %v: \nexpected %v \ngot %v", 111, expected, resp1) } + resp2 := resp[222] if expected, err := s.chain.GetHeaders(req2); err != nil { t.Fatalf("failed to get expected headers for request 2: %v", err) - } else if !headersMatch(expected, headers2.BlockHeadersRequest) { - t.Fatalf("header mismatch: \nexpected %v \ngot %v", expected, headers2) + } else if !headersMatch(expected, resp2.BlockHeadersRequest) { + t.Fatalf("header mismatch for request ID %v: \nexpected %v \ngot %v", 222, expected, resp2) } } func (s *Suite) TestSameRequestID(t *utesting.T) { t.Log(`This test requests block headers, performing two concurrent requests with the same request ID. The node should handle the request by responding to both requests.`) + conn, err := s.dialAndPeer(nil) if err != nil { t.Fatalf("peering failed: %v", err) @@ -289,7 +289,7 @@ same request ID. The node should handle the request by responding to both reques Origin: eth.HashOrNumber{ Number: 33, }, - Amount: 2, + Amount: 3, }, } @@ -301,35 +301,52 @@ same request ID. The node should handle the request by responding to both reques t.Fatalf("failed to write to connection: %v", err) } - // Wait for the responses. - headers1 := new(eth.BlockHeadersPacket) - if err := conn.ReadMsg(ethProto, eth.BlockHeadersMsg, &headers1); err != nil { - t.Fatalf("error reading from connection: %v", err) - } - if got, want := headers1.RequestId, request1.RequestId; got != want { - t.Fatalf("unexpected request id: got %d, want %d", got, want) - } - headers2 := new(eth.BlockHeadersPacket) - if err := conn.ReadMsg(ethProto, eth.BlockHeadersMsg, &headers2); err != nil { - t.Fatalf("error reading from connection: %v", err) - } - if got, want := headers2.RequestId, request2.RequestId; got != want { - t.Fatalf("unexpected request id: got %d, want %d", got, want) + // Wait for the responses. They can arrive in either order, and we can't tell them + // apart by their request ID, so use the number of headers instead. + resp, err := collectResponses(conn, 2, func(msg *eth.BlockHeadersPacket) uint64 { + id := uint64(len(msg.BlockHeadersRequest)) + if id != 2 && id != 3 { + t.Fatalf("invalid number of headers in response: %d", id) + } + return id + }) + if err != nil { + t.Fatal(err) } // Check if headers match. + resp1 := resp[2] if expected, err := s.chain.GetHeaders(request1); err != nil { - t.Fatalf("failed to get expected block headers: %v", err) - } else if !headersMatch(expected, headers1.BlockHeadersRequest) { - t.Fatalf("header mismatch: \nexpected %v \ngot %v", expected, headers1) + t.Fatalf("failed to get expected headers for request 1: %v", err) + } else if !headersMatch(expected, resp1.BlockHeadersRequest) { + t.Fatalf("headers mismatch: \nexpected %v \ngot %v", expected, resp1) } + resp2 := resp[3] if expected, err := s.chain.GetHeaders(request2); err != nil { - t.Fatalf("failed to get expected block headers: %v", err) - } else if !headersMatch(expected, headers2.BlockHeadersRequest) { - t.Fatalf("header mismatch: \nexpected %v \ngot %v", expected, headers2) + t.Fatalf("failed to get expected headers for request 2: %v", err) + } else if !headersMatch(expected, resp2.BlockHeadersRequest) { + t.Fatalf("headers mismatch: \nexpected %v \ngot %v", expected, resp2) } } +// collectResponses waits for n messages of type T on the given connection. +// The messsages are collected according to the 'identity' function. +func collectResponses[T any, P msgTypePtr[T]](conn *Conn, n int, identity func(P) uint64) (map[uint64]P, error) { + resp := make(map[uint64]P, n) + for range n { + r := new(T) + if err := conn.ReadMsg(ethProto, eth.BlockHeadersMsg, r); err != nil { + return resp, fmt.Errorf("read error: %v", err) + } + id := identity(r) + if resp[id] != nil { + return resp, fmt.Errorf("duplicate response %v", r) + } + resp[id] = r + } + return resp, nil +} + func (s *Suite) TestZeroRequestID(t *utesting.T) { t.Log(`This test sends a GetBlockHeaders message with a request-id of zero, and expects a response.`) @@ -887,7 +904,7 @@ func (s *Suite) makeBlobTxs(count, blobs int, discriminator byte) (txs types.Tra from, nonce := s.chain.GetSender(5) for i := 0; i < count; i++ { // Make blob data, max of 2 blobs per tx. - blobdata := make([]byte, blobs%3) + blobdata := make([]byte, min(blobs, 2)) for i := range blobdata { blobdata[i] = discriminator blobs -= 1 From 695c1445ab4eb26b630641a7bf6c27fceaa5fc2b Mon Sep 17 00:00:00 2001 From: phrwlk Date: Thu, 9 Oct 2025 03:59:06 +0300 Subject: [PATCH 17/23] core/rawdb: correct misleading comments for state history accessors (#32783) --- core/rawdb/accessors_state.go | 31 +++++++++++++++++++------------ 1 file changed, 19 insertions(+), 12 deletions(-) diff --git a/core/rawdb/accessors_state.go b/core/rawdb/accessors_state.go index 2359fb18f1..46aa5fd070 100644 --- a/core/rawdb/accessors_state.go +++ b/core/rawdb/accessors_state.go @@ -170,9 +170,11 @@ func ReadStateHistoryMetaList(db ethdb.AncientReaderOp, start uint64, count uint return db.AncientRange(stateHistoryMeta, start-1, count, 0) } -// ReadStateAccountIndex retrieves the state root corresponding to the specified -// state history. Compute the position of state history in freezer by minus one -// since the id of first state history starts from one(zero for initial state). +// ReadStateAccountIndex retrieves the account index blob for the specified +// state history. The index contains fixed-size entries with offsets and lengths +// into the concatenated account data table. Compute the position of state +// history in freezer by minus one since the id of first state history starts +// from one (zero for initial state). func ReadStateAccountIndex(db ethdb.AncientReaderOp, id uint64) []byte { blob, err := db.Ancient(stateHistoryAccountIndex, id-1) if err != nil { @@ -181,9 +183,11 @@ func ReadStateAccountIndex(db ethdb.AncientReaderOp, id uint64) []byte { return blob } -// ReadStateStorageIndex retrieves the state root corresponding to the specified -// state history. Compute the position of state history in freezer by minus one -// since the id of first state history starts from one(zero for initial state). +// ReadStateStorageIndex retrieves the storage index blob for the specified +// state history. The index contains fixed-size entries that locate storage slot +// data in the concatenated storage data table. Compute the position of state +// history in freezer by minus one since the id of first state history starts +// from one (zero for initial state). func ReadStateStorageIndex(db ethdb.AncientReaderOp, id uint64) []byte { blob, err := db.Ancient(stateHistoryStorageIndex, id-1) if err != nil { @@ -192,9 +196,10 @@ func ReadStateStorageIndex(db ethdb.AncientReaderOp, id uint64) []byte { return blob } -// ReadStateAccountHistory retrieves the state root corresponding to the specified -// state history. Compute the position of state history in freezer by minus one -// since the id of first state history starts from one(zero for initial state). +// ReadStateAccountHistory retrieves the concatenated account data blob for the +// specified state history. Offsets and lengths are resolved via the account +// index. Compute the position of state history in freezer by minus one since +// the id of first state history starts from one (zero for initial state). func ReadStateAccountHistory(db ethdb.AncientReaderOp, id uint64) []byte { blob, err := db.Ancient(stateHistoryAccountData, id-1) if err != nil { @@ -203,9 +208,11 @@ func ReadStateAccountHistory(db ethdb.AncientReaderOp, id uint64) []byte { return blob } -// ReadStateStorageHistory retrieves the state root corresponding to the specified -// state history. Compute the position of state history in freezer by minus one -// since the id of first state history starts from one(zero for initial state). +// ReadStateStorageHistory retrieves the concatenated storage slot data blob for +// the specified state history. Locations are resolved via the account and +// storage indexes. Compute the position of state history in freezer by minus +// one since the id of first state history starts from one (zero for initial +// state). func ReadStateStorageHistory(db ethdb.AncientReaderOp, id uint64) []byte { blob, err := db.Ancient(stateHistoryStorageData, id-1) if err != nil { From a1b8e4880d24d5e618b0637defa380d75e30c831 Mon Sep 17 00:00:00 2001 From: CertiK <138698582+CertiK-Geth@users.noreply.github.com> Date: Thu, 9 Oct 2025 17:34:30 +0800 Subject: [PATCH 18/23] eth/filters: terminate pending tx subscription on error (#32794) Fixes issue #32793. When the pending tx subscription ends, the filter is removed from `api.filters`, but it is not terminated. There is no other way to terminate it, so the subscription will leak, and potentially block the producer side. --- eth/filters/api.go | 1 + 1 file changed, 1 insertion(+) diff --git a/eth/filters/api.go b/eth/filters/api.go index d678c40389..334a19f0b5 100644 --- a/eth/filters/api.go +++ b/eth/filters/api.go @@ -152,6 +152,7 @@ func (api *FilterAPI) NewPendingTransactionFilter(fullTx *bool) rpc.ID { api.filtersMu.Lock() delete(api.filters, pendingTxSub.ID) api.filtersMu.Unlock() + pendingTxSub.Unsubscribe() return } } From 11208553ddded439c708fa430e559675f25052e7 Mon Sep 17 00:00:00 2001 From: 10gic Date: Thu, 9 Oct 2025 20:14:53 +0800 Subject: [PATCH 19/23] eth/filters: add `transactionReceipts` subscription (#32697) - Introduce a new subscription kind `transactionReceipts` to allow clients to receive transaction receipts over WebSocket as soon as they are available. - Accept optional `transactionHashes` filter to subscribe to receipts for specific transactions; an empty or omitted filter subscribes to all receipts. - Preserve the same receipt format as returned by `eth_getTransactionReceipt`. - Avoid additional HTTP polling, reducing RPC load and latency. --------- Co-authored-by: Sina Mahmoodi --- core/blockchain.go | 26 +++++- core/events.go | 4 +- eth/filters/api.go | 68 ++++++++++++++ eth/filters/filter.go | 68 ++++++++++++++ eth/filters/filter_system.go | 35 ++++++++ eth/filters/filter_system_test.go | 141 ++++++++++++++++++++++++++++++ internal/ethapi/api.go | 8 +- 7 files changed, 341 insertions(+), 9 deletions(-) diff --git a/core/blockchain.go b/core/blockchain.go index 71eb4c45a2..b7acd12aca 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -1690,7 +1690,12 @@ func (bc *BlockChain) writeBlockAndSetHead(block *types.Block, receipts []*types // Set new head. bc.writeHeadBlock(block) - bc.chainFeed.Send(ChainEvent{Header: block.Header()}) + bc.chainFeed.Send(ChainEvent{ + Header: block.Header(), + Receipts: receipts, + Transactions: block.Transactions(), + }) + if len(logs) > 0 { bc.logsFeed.Send(logs) } @@ -2342,6 +2347,13 @@ func (bc *BlockChain) recoverAncestors(block *types.Block, makeWitness bool) (co // collectLogs collects the logs that were generated or removed during the // processing of a block. These logs are later announced as deleted or reborn. func (bc *BlockChain) collectLogs(b *types.Block, removed bool) []*types.Log { + _, logs := bc.collectReceiptsAndLogs(b, removed) + return logs +} + +// collectReceiptsAndLogs retrieves receipts from the database and returns both receipts and logs. +// This avoids duplicate database reads when both are needed. +func (bc *BlockChain) collectReceiptsAndLogs(b *types.Block, removed bool) ([]*types.Receipt, []*types.Log) { var blobGasPrice *big.Int if b.ExcessBlobGas() != nil { blobGasPrice = eip4844.CalcBlobFee(bc.chainConfig, b.Header()) @@ -2359,7 +2371,7 @@ func (bc *BlockChain) collectLogs(b *types.Block, removed bool) []*types.Log { logs = append(logs, log) } } - return logs + return receipts, logs } // reorg takes two blocks, an old chain and a new chain and will reconstruct the @@ -2588,8 +2600,14 @@ func (bc *BlockChain) SetCanonical(head *types.Block) (common.Hash, error) { bc.writeHeadBlock(head) // Emit events - logs := bc.collectLogs(head, false) - bc.chainFeed.Send(ChainEvent{Header: head.Header()}) + receipts, logs := bc.collectReceiptsAndLogs(head, false) + + bc.chainFeed.Send(ChainEvent{ + Header: head.Header(), + Receipts: receipts, + Transactions: head.Transactions(), + }) + if len(logs) > 0 { bc.logsFeed.Send(logs) } diff --git a/core/events.go b/core/events.go index 5ad2cb1f7b..ef0de32426 100644 --- a/core/events.go +++ b/core/events.go @@ -27,7 +27,9 @@ type NewTxsEvent struct{ Txs []*types.Transaction } type RemovedLogsEvent struct{ Logs []*types.Log } type ChainEvent struct { - Header *types.Header + Header *types.Header + Receipts []*types.Receipt + Transactions []*types.Transaction } type ChainHeadEvent struct { diff --git a/eth/filters/api.go b/eth/filters/api.go index 334a19f0b5..9f9209aea7 100644 --- a/eth/filters/api.go +++ b/eth/filters/api.go @@ -43,6 +43,7 @@ var ( errPendingLogsUnsupported = errors.New("pending logs are not supported") errExceedMaxTopics = errors.New("exceed max topics") errExceedLogQueryLimit = errors.New("exceed max addresses or topics per search position") + errExceedMaxTxHashes = errors.New("exceed max number of transaction hashes allowed per transactionReceipts subscription") ) const ( @@ -50,6 +51,8 @@ const ( maxTopics = 4 // The maximum number of allowed topics within a topic criteria maxSubTopics = 1000 + // The maximum number of transaction hash criteria allowed in a single subscription + maxTxHashes = 200 ) // filter is a helper struct that holds meta information over the filter type @@ -296,6 +299,71 @@ func (api *FilterAPI) Logs(ctx context.Context, crit FilterCriteria) (*rpc.Subsc return rpcSub, nil } +// TransactionReceiptsFilter defines criteria for transaction receipts subscription. +// If TransactionHashes is nil or empty, receipts for all transactions included in new blocks will be delivered. +// Otherwise, only receipts for the specified transactions will be delivered. +type TransactionReceiptsFilter struct { + TransactionHashes []common.Hash `json:"transactionHashes,omitempty"` +} + +// TransactionReceipts creates a subscription that fires transaction receipts when transactions are included in blocks. +func (api *FilterAPI) TransactionReceipts(ctx context.Context, filter *TransactionReceiptsFilter) (*rpc.Subscription, error) { + notifier, supported := rpc.NotifierFromContext(ctx) + if !supported { + return &rpc.Subscription{}, rpc.ErrNotificationsUnsupported + } + + // Validate transaction hashes limit + if filter != nil && len(filter.TransactionHashes) > maxTxHashes { + return nil, errExceedMaxTxHashes + } + + var ( + rpcSub = notifier.CreateSubscription() + matchedReceipts = make(chan []*ReceiptWithTx) + txHashes []common.Hash + ) + + if filter != nil { + txHashes = filter.TransactionHashes + } + + receiptsSub := api.events.SubscribeTransactionReceipts(txHashes, matchedReceipts) + + go func() { + defer receiptsSub.Unsubscribe() + + signer := types.LatestSigner(api.sys.backend.ChainConfig()) + + for { + select { + case receiptsWithTxs := <-matchedReceipts: + if len(receiptsWithTxs) > 0 { + // Convert to the same format as eth_getTransactionReceipt + marshaledReceipts := make([]map[string]interface{}, len(receiptsWithTxs)) + for i, receiptWithTx := range receiptsWithTxs { + marshaledReceipts[i] = ethapi.MarshalReceipt( + receiptWithTx.Receipt, + receiptWithTx.Receipt.BlockHash, + receiptWithTx.Receipt.BlockNumber.Uint64(), + signer, + receiptWithTx.Transaction, + int(receiptWithTx.Receipt.TransactionIndex), + ) + } + + // Send a batch of tx receipts in one notification + notifier.Notify(rpcSub.ID, marshaledReceipts) + } + case <-rpcSub.Err(): + return + } + } + }() + + return rpcSub, nil +} + // FilterCriteria represents a request to create a new filter. // Same as ethereum.FilterQuery but with UnmarshalJSON() method. type FilterCriteria ethereum.FilterQuery diff --git a/eth/filters/filter.go b/eth/filters/filter.go index 1a9918d0ee..02399bc801 100644 --- a/eth/filters/filter.go +++ b/eth/filters/filter.go @@ -25,6 +25,7 @@ import ( "time" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core/filtermaps" "github.com/ethereum/go-ethereum/core/history" "github.com/ethereum/go-ethereum/core/types" @@ -551,3 +552,70 @@ func bloomFilter(bloom types.Bloom, addresses []common.Address, topics [][]commo } return true } + +// ReceiptWithTx contains a receipt and its corresponding transaction +type ReceiptWithTx struct { + Receipt *types.Receipt + Transaction *types.Transaction +} + +// filterReceipts returns the receipts matching the given criteria +// In addition to returning receipts, it also returns the corresponding transactions. +// This is because receipts only contain low-level data, while user-facing data +// may require additional information from the Transaction. +func filterReceipts(txHashes []common.Hash, ev core.ChainEvent) []*ReceiptWithTx { + var ret []*ReceiptWithTx + + receipts := ev.Receipts + txs := ev.Transactions + + if len(receipts) != len(txs) { + log.Warn("Receipts and transactions length mismatch", "receipts", len(receipts), "transactions", len(txs)) + return ret + } + + if len(txHashes) == 0 { + // No filter, send all receipts with their transactions. + ret = make([]*ReceiptWithTx, len(receipts)) + for i, receipt := range receipts { + ret[i] = &ReceiptWithTx{ + Receipt: receipt, + Transaction: txs[i], + } + } + } else if len(txHashes) == 1 { + // Filter by single transaction hash. + // This is a common case, so we distinguish it from filtering by multiple tx hashes and made a small optimization. + for i, receipt := range receipts { + if receipt.TxHash == txHashes[0] { + ret = append(ret, &ReceiptWithTx{ + Receipt: receipt, + Transaction: txs[i], + }) + break + } + } + } else { + // Filter by multiple transaction hashes. + txHashMap := make(map[common.Hash]bool, len(txHashes)) + for _, hash := range txHashes { + txHashMap[hash] = true + } + + for i, receipt := range receipts { + if txHashMap[receipt.TxHash] { + ret = append(ret, &ReceiptWithTx{ + Receipt: receipt, + Transaction: txs[i], + }) + + // Early exit if all receipts are found + if len(ret) == len(txHashes) { + break + } + } + } + } + + return ret +} diff --git a/eth/filters/filter_system.go b/eth/filters/filter_system.go index ecf1c870c1..02783fa5ec 100644 --- a/eth/filters/filter_system.go +++ b/eth/filters/filter_system.go @@ -158,6 +158,8 @@ const ( PendingTransactionsSubscription // BlocksSubscription queries hashes for blocks that are imported BlocksSubscription + // TransactionReceiptsSubscription queries for transaction receipts when transactions are included in blocks + TransactionReceiptsSubscription // LastIndexSubscription keeps track of the last index LastIndexSubscription ) @@ -182,6 +184,8 @@ type subscription struct { logs chan []*types.Log txs chan []*types.Transaction headers chan *types.Header + receipts chan []*ReceiptWithTx + txHashes []common.Hash // contains transaction hashes for transactionReceipts subscription filtering installed chan struct{} // closed when the filter is installed err chan error // closed when the filter is uninstalled } @@ -268,6 +272,7 @@ func (sub *Subscription) Unsubscribe() { case <-sub.f.logs: case <-sub.f.txs: case <-sub.f.headers: + case <-sub.f.receipts: } } @@ -353,6 +358,7 @@ func (es *EventSystem) subscribeLogs(crit ethereum.FilterQuery, logs chan []*typ logs: logs, txs: make(chan []*types.Transaction), headers: make(chan *types.Header), + receipts: make(chan []*ReceiptWithTx), installed: make(chan struct{}), err: make(chan error), } @@ -369,6 +375,7 @@ func (es *EventSystem) SubscribeNewHeads(headers chan *types.Header) *Subscripti logs: make(chan []*types.Log), txs: make(chan []*types.Transaction), headers: headers, + receipts: make(chan []*ReceiptWithTx), installed: make(chan struct{}), err: make(chan error), } @@ -385,6 +392,26 @@ func (es *EventSystem) SubscribePendingTxs(txs chan []*types.Transaction) *Subsc logs: make(chan []*types.Log), txs: txs, headers: make(chan *types.Header), + receipts: make(chan []*ReceiptWithTx), + installed: make(chan struct{}), + err: make(chan error), + } + return es.subscribe(sub) +} + +// SubscribeTransactionReceipts creates a subscription that writes transaction receipts for +// transactions when they are included in blocks. If txHashes is provided, only receipts +// for those specific transaction hashes will be delivered. +func (es *EventSystem) SubscribeTransactionReceipts(txHashes []common.Hash, receipts chan []*ReceiptWithTx) *Subscription { + sub := &subscription{ + id: rpc.NewID(), + typ: TransactionReceiptsSubscription, + created: time.Now(), + logs: make(chan []*types.Log), + txs: make(chan []*types.Transaction), + headers: make(chan *types.Header), + receipts: receipts, + txHashes: txHashes, installed: make(chan struct{}), err: make(chan error), } @@ -415,6 +442,14 @@ func (es *EventSystem) handleChainEvent(filters filterIndex, ev core.ChainEvent) for _, f := range filters[BlocksSubscription] { f.headers <- ev.Header } + + // Handle transaction receipts subscriptions when a new block is added + for _, f := range filters[TransactionReceiptsSubscription] { + matchedReceipts := filterReceipts(f.txHashes, ev) + if len(matchedReceipts) > 0 { + f.receipts <- matchedReceipts + } + } } // eventLoop (un)installs filters and processes mux events. diff --git a/eth/filters/filter_system_test.go b/eth/filters/filter_system_test.go index 0048e74995..e5a1a2b25f 100644 --- a/eth/filters/filter_system_test.go +++ b/eth/filters/filter_system_test.go @@ -31,6 +31,7 @@ import ( "github.com/ethereum/go-ethereum/core/filtermaps" "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/event" "github.com/ethereum/go-ethereum/internal/ethapi" @@ -781,3 +782,143 @@ func TestPendingTxFilterDeadlock(t *testing.T) { } } } + +// TestTransactionReceiptsSubscription tests the transaction receipts subscription functionality +func TestTransactionReceiptsSubscription(t *testing.T) { + t.Parallel() + + const txNum = 5 + + // Setup test environment + var ( + db = rawdb.NewMemoryDatabase() + backend, sys = newTestFilterSystem(db, Config{}) + api = NewFilterAPI(sys) + key1, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") + addr1 = crypto.PubkeyToAddress(key1.PublicKey) + signer = types.NewLondonSigner(big.NewInt(1)) + genesis = &core.Genesis{ + Alloc: types.GenesisAlloc{addr1: {Balance: big.NewInt(1000000000000000000)}}, // 1 ETH + Config: params.TestChainConfig, + BaseFee: big.NewInt(params.InitialBaseFee), + } + _, chain, _ = core.GenerateChainWithGenesis(genesis, ethash.NewFaker(), 1, func(i int, gen *core.BlockGen) { + // Add transactions to the block + for j := 0; j < txNum; j++ { + toAddr := common.HexToAddress("0xb794f5ea0ba39494ce83a213fffba74279579268") + tx, _ := types.SignTx(types.NewTx(&types.LegacyTx{ + Nonce: uint64(j), + GasPrice: gen.BaseFee(), + Gas: 21000, + To: &toAddr, + Value: big.NewInt(1000), + Data: nil, + }), signer, key1) + gen.AddTx(tx) + } + }) + ) + + // Insert the blocks into the chain + blockchain, err := core.NewBlockChain(db, genesis, ethash.NewFaker(), nil) + if err != nil { + t.Fatalf("failed to create tester chain: %v", err) + } + if n, err := blockchain.InsertChain(chain); err != nil { + t.Fatalf("block %d: failed to insert into chain: %v", n, err) + } + + // Prepare test data + receipts := blockchain.GetReceiptsByHash(chain[0].Hash()) + if receipts == nil { + t.Fatalf("failed to get receipts") + } + + chainEvent := core.ChainEvent{ + Header: chain[0].Header(), + Receipts: receipts, + Transactions: chain[0].Transactions(), + } + + txHashes := make([]common.Hash, txNum) + for i := 0; i < txNum; i++ { + txHashes[i] = chain[0].Transactions()[i].Hash() + } + + testCases := []struct { + name string + filterTxHashes []common.Hash + expectedReceiptTxHashes []common.Hash + expectError bool + }{ + { + name: "no filter - should return all receipts", + filterTxHashes: nil, + expectedReceiptTxHashes: txHashes, + expectError: false, + }, + { + name: "single tx hash filter", + filterTxHashes: []common.Hash{txHashes[0]}, + expectedReceiptTxHashes: []common.Hash{txHashes[0]}, + expectError: false, + }, + { + name: "multiple tx hashes filter", + filterTxHashes: []common.Hash{txHashes[0], txHashes[1], txHashes[2]}, + expectedReceiptTxHashes: []common.Hash{txHashes[0], txHashes[1], txHashes[2]}, + expectError: false, + }, + } + + // Run test cases + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + receiptsChan := make(chan []*ReceiptWithTx) + sub := api.events.SubscribeTransactionReceipts(tc.filterTxHashes, receiptsChan) + + // Send chain event + backend.chainFeed.Send(chainEvent) + + // Wait for receipts + timeout := time.After(1 * time.Second) + var receivedReceipts []*types.Receipt + for { + select { + case receiptsWithTx := <-receiptsChan: + for _, receiptWithTx := range receiptsWithTx { + receivedReceipts = append(receivedReceipts, receiptWithTx.Receipt) + } + case <-timeout: + t.Fatalf("timeout waiting for receipts") + } + if len(receivedReceipts) >= len(tc.expectedReceiptTxHashes) { + break + } + } + + // Verify receipt count + if len(receivedReceipts) != len(tc.expectedReceiptTxHashes) { + t.Errorf("Expected %d receipts, got %d", len(tc.expectedReceiptTxHashes), len(receivedReceipts)) + } + + // Verify specific transaction hashes are present + if tc.expectedReceiptTxHashes != nil { + receivedHashes := make(map[common.Hash]bool) + for _, receipt := range receivedReceipts { + receivedHashes[receipt.TxHash] = true + } + + for _, expectedHash := range tc.expectedReceiptTxHashes { + if !receivedHashes[expectedHash] { + t.Errorf("Expected receipt for tx %x not found", expectedHash) + } + } + } + + // Cleanup + sub.Unsubscribe() + <-sub.Err() + }) + } +} diff --git a/internal/ethapi/api.go b/internal/ethapi/api.go index c3f267027c..a2cb28d3b2 100644 --- a/internal/ethapi/api.go +++ b/internal/ethapi/api.go @@ -627,7 +627,7 @@ func (api *BlockChainAPI) GetBlockReceipts(ctx context.Context, blockNrOrHash rp result := make([]map[string]interface{}, len(receipts)) for i, receipt := range receipts { - result[i] = marshalReceipt(receipt, block.Hash(), block.NumberU64(), signer, txs[i], i) + result[i] = MarshalReceipt(receipt, block.Hash(), block.NumberU64(), signer, txs[i], i) } return result, nil } @@ -1488,11 +1488,11 @@ func (api *TransactionAPI) GetTransactionReceipt(ctx context.Context, hash commo return nil, err } // Derive the sender. - return marshalReceipt(receipt, blockHash, blockNumber, api.signer, tx, int(index)), nil + return MarshalReceipt(receipt, blockHash, blockNumber, api.signer, tx, int(index)), nil } -// marshalReceipt marshals a transaction receipt into a JSON object. -func marshalReceipt(receipt *types.Receipt, blockHash common.Hash, blockNumber uint64, signer types.Signer, tx *types.Transaction, txIndex int) map[string]interface{} { +// MarshalReceipt marshals a transaction receipt into a JSON object. +func MarshalReceipt(receipt *types.Receipt, blockHash common.Hash, blockNumber uint64, signer types.Signer, tx *types.Transaction, txIndex int) map[string]interface{} { from, _ := types.Sender(signer, tx) fields := map[string]interface{}{ From 4d6d5a3abf7753009255749407c32aefbf3bff78 Mon Sep 17 00:00:00 2001 From: Csaba Kiraly Date: Fri, 10 Oct 2025 07:40:10 +0200 Subject: [PATCH 20/23] core/txpool/legacypool: fix validTxMeter to count transactions (#32845) invalidTxMeter was counting txs, while validTxMeter was counting accounts. Better make the two comparable. --------- Signed-off-by: Csaba Kiraly --- core/txpool/legacypool/legacypool.go | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/core/txpool/legacypool/legacypool.go b/core/txpool/legacypool/legacypool.go index 80a9faf23f..e199d21c7a 100644 --- a/core/txpool/legacypool/legacypool.go +++ b/core/txpool/legacypool/legacypool.go @@ -984,17 +984,24 @@ func (pool *LegacyPool) Add(txs []*types.Transaction, sync bool) []error { // addTxsLocked attempts to queue a batch of transactions if they are valid. // The transaction pool lock must be held. +// Returns the error for each tx, and the set of accounts that might became promotable. func (pool *LegacyPool) addTxsLocked(txs []*types.Transaction) ([]error, *accountSet) { - dirty := newAccountSet(pool.signer) - errs := make([]error, len(txs)) + var ( + dirty = newAccountSet(pool.signer) + errs = make([]error, len(txs)) + valid int64 + ) for i, tx := range txs { replaced, err := pool.add(tx) errs[i] = err - if err == nil && !replaced { - dirty.addTx(tx) + if err == nil { + if !replaced { + dirty.addTx(tx) + } + valid++ } } - validTxMeter.Mark(int64(len(dirty.accounts))) + validTxMeter.Mark(valid) return errs, dirty } From ed264a1f198ea4172b4f2fe622bae5987f114561 Mon Sep 17 00:00:00 2001 From: cui Date: Fri, 10 Oct 2025 13:48:25 +0800 Subject: [PATCH 21/23] eth/protocols/snap: optimize incHash (#32748) --- eth/protocols/snap/range.go | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/eth/protocols/snap/range.go b/eth/protocols/snap/range.go index 8c98c71d50..f32cca8d23 100644 --- a/eth/protocols/snap/range.go +++ b/eth/protocols/snap/range.go @@ -74,8 +74,11 @@ func (r *hashRange) End() common.Hash { // incHash returns the next hash, in lexicographical order (a.k.a plus one) func incHash(h common.Hash) common.Hash { - var a uint256.Int - a.SetBytes32(h[:]) - a.AddUint64(&a, 1) - return common.Hash(a.Bytes32()) + for i := len(h) - 1; i >= 0; i-- { + h[i]++ + if h[i] != 0 { + break + } + } + return h } From de24450dbf0887032eacdee7da130b5e038be5cb Mon Sep 17 00:00:00 2001 From: rjl493456442 Date: Fri, 10 Oct 2025 14:51:27 +0800 Subject: [PATCH 22/23] core/rawdb, triedb/pathdb: introduce trienode history (#32596) It's a pull request based on the #32523 , implementing the structure of trienode history. --- core/rawdb/accessors_history.go | 95 +++- core/rawdb/accessors_state.go | 73 +++ core/rawdb/ancient_scheme.go | 50 +- core/rawdb/schema.go | 43 +- triedb/pathdb/database.go | 4 +- triedb/pathdb/history.go | 57 +- triedb/pathdb/history_index.go | 12 + triedb/pathdb/history_indexer.go | 76 ++- triedb/pathdb/history_state.go | 6 +- triedb/pathdb/history_state_test.go | 20 +- triedb/pathdb/history_trienode.go | 730 ++++++++++++++++++++++++ triedb/pathdb/history_trienode_test.go | 736 +++++++++++++++++++++++++ triedb/pathdb/metrics.go | 19 +- 13 files changed, 1850 insertions(+), 71 deletions(-) create mode 100644 triedb/pathdb/history_trienode.go create mode 100644 triedb/pathdb/history_trienode_test.go diff --git a/core/rawdb/accessors_history.go b/core/rawdb/accessors_history.go index cf1073f387..95a8907edc 100644 --- a/core/rawdb/accessors_history.go +++ b/core/rawdb/accessors_history.go @@ -46,6 +46,27 @@ func DeleteStateHistoryIndexMetadata(db ethdb.KeyValueWriter) { } } +// ReadTrienodeHistoryIndexMetadata retrieves the metadata of trienode history index. +func ReadTrienodeHistoryIndexMetadata(db ethdb.KeyValueReader) []byte { + data, _ := db.Get(headTrienodeHistoryIndexKey) + return data +} + +// WriteTrienodeHistoryIndexMetadata stores the metadata of trienode history index +// into database. +func WriteTrienodeHistoryIndexMetadata(db ethdb.KeyValueWriter, blob []byte) { + if err := db.Put(headTrienodeHistoryIndexKey, blob); err != nil { + log.Crit("Failed to store the metadata of trienode history index", "err", err) + } +} + +// DeleteTrienodeHistoryIndexMetadata removes the metadata of trienode history index. +func DeleteTrienodeHistoryIndexMetadata(db ethdb.KeyValueWriter) { + if err := db.Delete(headTrienodeHistoryIndexKey); err != nil { + log.Crit("Failed to delete the metadata of trienode history index", "err", err) + } +} + // ReadAccountHistoryIndex retrieves the account history index with the provided // account address. func ReadAccountHistoryIndex(db ethdb.KeyValueReader, addressHash common.Hash) []byte { @@ -95,6 +116,30 @@ func DeleteStorageHistoryIndex(db ethdb.KeyValueWriter, addressHash common.Hash, } } +// ReadTrienodeHistoryIndex retrieves the trienode history index with the provided +// account address and storage key hash. +func ReadTrienodeHistoryIndex(db ethdb.KeyValueReader, addressHash common.Hash, path []byte) []byte { + data, err := db.Get(trienodeHistoryIndexKey(addressHash, path)) + if err != nil || len(data) == 0 { + return nil + } + return data +} + +// WriteTrienodeHistoryIndex writes the provided trienode history index into database. +func WriteTrienodeHistoryIndex(db ethdb.KeyValueWriter, addressHash common.Hash, path []byte, data []byte) { + if err := db.Put(trienodeHistoryIndexKey(addressHash, path), data); err != nil { + log.Crit("Failed to store trienode history index", "err", err) + } +} + +// DeleteTrienodeHistoryIndex deletes the specified trienode index from the database. +func DeleteTrienodeHistoryIndex(db ethdb.KeyValueWriter, addressHash common.Hash, path []byte) { + if err := db.Delete(trienodeHistoryIndexKey(addressHash, path)); err != nil { + log.Crit("Failed to delete trienode history index", "err", err) + } +} + // ReadAccountHistoryIndexBlock retrieves the index block with the provided // account address along with the block id. func ReadAccountHistoryIndexBlock(db ethdb.KeyValueReader, addressHash common.Hash, blockID uint32) []byte { @@ -143,6 +188,30 @@ func DeleteStorageHistoryIndexBlock(db ethdb.KeyValueWriter, addressHash common. } } +// ReadTrienodeHistoryIndexBlock retrieves the index block with the provided state +// identifier along with the block id. +func ReadTrienodeHistoryIndexBlock(db ethdb.KeyValueReader, addressHash common.Hash, path []byte, blockID uint32) []byte { + data, err := db.Get(trienodeHistoryIndexBlockKey(addressHash, path, blockID)) + if err != nil || len(data) == 0 { + return nil + } + return data +} + +// WriteTrienodeHistoryIndexBlock writes the provided index block into database. +func WriteTrienodeHistoryIndexBlock(db ethdb.KeyValueWriter, addressHash common.Hash, path []byte, id uint32, data []byte) { + if err := db.Put(trienodeHistoryIndexBlockKey(addressHash, path, id), data); err != nil { + log.Crit("Failed to store trienode index block", "err", err) + } +} + +// DeleteTrienodeHistoryIndexBlock deletes the specified index block from the database. +func DeleteTrienodeHistoryIndexBlock(db ethdb.KeyValueWriter, addressHash common.Hash, path []byte, id uint32) { + if err := db.Delete(trienodeHistoryIndexBlockKey(addressHash, path, id)); err != nil { + log.Crit("Failed to delete trienode index block", "err", err) + } +} + // increaseKey increase the input key by one bit. Return nil if the entire // addition operation overflows. func increaseKey(key []byte) []byte { @@ -155,14 +224,26 @@ func increaseKey(key []byte) []byte { return nil } -// DeleteStateHistoryIndex completely removes all history indexing data, including +// DeleteStateHistoryIndexes completely removes all history indexing data, including // indexes for accounts and storages. -// -// Note, this method assumes the storage space with prefix `StateHistoryIndexPrefix` -// is exclusively occupied by the history indexing data! -func DeleteStateHistoryIndex(db ethdb.KeyValueRangeDeleter) { - start := StateHistoryIndexPrefix - limit := increaseKey(bytes.Clone(StateHistoryIndexPrefix)) +func DeleteStateHistoryIndexes(db ethdb.KeyValueRangeDeleter) { + DeleteHistoryByRange(db, StateHistoryAccountMetadataPrefix) + DeleteHistoryByRange(db, StateHistoryStorageMetadataPrefix) + DeleteHistoryByRange(db, StateHistoryAccountBlockPrefix) + DeleteHistoryByRange(db, StateHistoryStorageBlockPrefix) +} + +// DeleteTrienodeHistoryIndexes completely removes all trienode history indexing data. +func DeleteTrienodeHistoryIndexes(db ethdb.KeyValueRangeDeleter) { + DeleteHistoryByRange(db, TrienodeHistoryMetadataPrefix) + DeleteHistoryByRange(db, TrienodeHistoryBlockPrefix) +} + +// DeleteHistoryByRange completely removes all database entries with the specific prefix. +// Note, this method assumes the space with the given prefix is exclusively occupied! +func DeleteHistoryByRange(db ethdb.KeyValueRangeDeleter, prefix []byte) { + start := prefix + limit := increaseKey(bytes.Clone(prefix)) // Try to remove the data in the range by a loop, as the leveldb // doesn't support the native range deletion. diff --git a/core/rawdb/accessors_state.go b/core/rawdb/accessors_state.go index 46aa5fd070..298ad04f40 100644 --- a/core/rawdb/accessors_state.go +++ b/core/rawdb/accessors_state.go @@ -299,3 +299,76 @@ func WriteStateHistory(db ethdb.AncientWriter, id uint64, meta []byte, accountIn }) return err } + +// ReadTrienodeHistory retrieves the trienode history corresponding to the specified id. +// Compute the position of trienode history in freezer by minus one since the id of first +// trienode history starts from one(zero for initial state). +func ReadTrienodeHistory(db ethdb.AncientReaderOp, id uint64) ([]byte, []byte, []byte, error) { + header, err := db.Ancient(trienodeHistoryHeaderTable, id-1) + if err != nil { + return nil, nil, nil, err + } + keySection, err := db.Ancient(trienodeHistoryKeySectionTable, id-1) + if err != nil { + return nil, nil, nil, err + } + valueSection, err := db.Ancient(trienodeHistoryValueSectionTable, id-1) + if err != nil { + return nil, nil, nil, err + } + return header, keySection, valueSection, nil +} + +// ReadTrienodeHistoryHeader retrieves the header section of trienode history. +func ReadTrienodeHistoryHeader(db ethdb.AncientReaderOp, id uint64) ([]byte, error) { + return db.Ancient(trienodeHistoryHeaderTable, id-1) +} + +// ReadTrienodeHistoryKeySection retrieves the key section of trienode history. +func ReadTrienodeHistoryKeySection(db ethdb.AncientReaderOp, id uint64) ([]byte, error) { + return db.Ancient(trienodeHistoryKeySectionTable, id-1) +} + +// ReadTrienodeHistoryValueSection retrieves the value section of trienode history. +func ReadTrienodeHistoryValueSection(db ethdb.AncientReaderOp, id uint64) ([]byte, error) { + return db.Ancient(trienodeHistoryValueSectionTable, id-1) +} + +// ReadTrienodeHistoryList retrieves the a list of trienode history corresponding +// to the specified range. +// Compute the position of trienode history in freezer by minus one since the id +// of first trienode history starts from one(zero for initial state). +func ReadTrienodeHistoryList(db ethdb.AncientReaderOp, start uint64, count uint64) ([][]byte, [][]byte, [][]byte, error) { + header, err := db.AncientRange(trienodeHistoryHeaderTable, start-1, count, 0) + if err != nil { + return nil, nil, nil, err + } + keySection, err := db.AncientRange(trienodeHistoryKeySectionTable, start-1, count, 0) + if err != nil { + return nil, nil, nil, err + } + valueSection, err := db.AncientRange(trienodeHistoryValueSectionTable, start-1, count, 0) + if err != nil { + return nil, nil, nil, err + } + if len(header) != len(keySection) || len(header) != len(valueSection) { + return nil, nil, nil, errors.New("trienode history is corrupted") + } + return header, keySection, valueSection, nil +} + +// WriteTrienodeHistory writes the provided trienode history to database. +// Compute the position of trienode history in freezer by minus one since +// the id of first state history starts from one(zero for initial state). +func WriteTrienodeHistory(db ethdb.AncientWriter, id uint64, header []byte, keySection []byte, valueSection []byte) error { + _, err := db.ModifyAncients(func(op ethdb.AncientWriteOp) error { + if err := op.AppendRaw(trienodeHistoryHeaderTable, id-1, header); err != nil { + return err + } + if err := op.AppendRaw(trienodeHistoryKeySectionTable, id-1, keySection); err != nil { + return err + } + return op.AppendRaw(trienodeHistoryValueSectionTable, id-1, valueSection) + }) + return err +} diff --git a/core/rawdb/ancient_scheme.go b/core/rawdb/ancient_scheme.go index 1ffebed3e7..afec7848c8 100644 --- a/core/rawdb/ancient_scheme.go +++ b/core/rawdb/ancient_scheme.go @@ -75,15 +75,38 @@ var stateFreezerTableConfigs = map[string]freezerTableConfig{ stateHistoryStorageData: {noSnappy: false, prunable: true}, } +const ( + trienodeHistoryHeaderTable = "trienode.header" + trienodeHistoryKeySectionTable = "trienode.key" + trienodeHistoryValueSectionTable = "trienode.value" +) + +// trienodeFreezerTableConfigs configures the settings for tables in the trienode freezer. +var trienodeFreezerTableConfigs = map[string]freezerTableConfig{ + trienodeHistoryHeaderTable: {noSnappy: false, prunable: true}, + + // Disable snappy compression to allow efficient partial read. + trienodeHistoryKeySectionTable: {noSnappy: true, prunable: true}, + + // Disable snappy compression to allow efficient partial read. + trienodeHistoryValueSectionTable: {noSnappy: true, prunable: true}, +} + // The list of identifiers of ancient stores. var ( - ChainFreezerName = "chain" // the folder name of chain segment ancient store. - MerkleStateFreezerName = "state" // the folder name of state history ancient store. - VerkleStateFreezerName = "state_verkle" // the folder name of state history ancient store. + ChainFreezerName = "chain" // the folder name of chain segment ancient store. + MerkleStateFreezerName = "state" // the folder name of state history ancient store. + VerkleStateFreezerName = "state_verkle" // the folder name of state history ancient store. + MerkleTrienodeFreezerName = "trienode" // the folder name of trienode history ancient store. + VerkleTrienodeFreezerName = "trienode_verkle" // the folder name of trienode history ancient store. ) // freezers the collections of all builtin freezers. -var freezers = []string{ChainFreezerName, MerkleStateFreezerName, VerkleStateFreezerName} +var freezers = []string{ + ChainFreezerName, + MerkleStateFreezerName, VerkleStateFreezerName, + MerkleTrienodeFreezerName, VerkleTrienodeFreezerName, +} // NewStateFreezer initializes the ancient store for state history. // @@ -103,3 +126,22 @@ func NewStateFreezer(ancientDir string, verkle bool, readOnly bool) (ethdb.Reset } return newResettableFreezer(name, "eth/db/state", readOnly, stateHistoryTableSize, stateFreezerTableConfigs) } + +// NewTrienodeFreezer initializes the ancient store for trienode history. +// +// - if the empty directory is given, initializes the pure in-memory +// trienode freezer (e.g. dev mode). +// - if non-empty directory is given, initializes the regular file-based +// trienode freezer. +func NewTrienodeFreezer(ancientDir string, verkle bool, readOnly bool) (ethdb.ResettableAncientStore, error) { + if ancientDir == "" { + return NewMemoryFreezer(readOnly, trienodeFreezerTableConfigs), nil + } + var name string + if verkle { + name = filepath.Join(ancientDir, VerkleTrienodeFreezerName) + } else { + name = filepath.Join(ancientDir, MerkleTrienodeFreezerName) + } + return newResettableFreezer(name, "eth/db/trienode", readOnly, stateHistoryTableSize, trienodeFreezerTableConfigs) +} diff --git a/core/rawdb/schema.go b/core/rawdb/schema.go index 9a17e1c173..d9140c5fd6 100644 --- a/core/rawdb/schema.go +++ b/core/rawdb/schema.go @@ -80,6 +80,10 @@ var ( // been indexed. headStateHistoryIndexKey = []byte("LastStateHistoryIndex") + // headTrienodeHistoryIndexKey tracks the ID of the latest state history that has + // been indexed. + headTrienodeHistoryIndexKey = []byte("LastTrienodeHistoryIndex") + // txIndexTailKey tracks the oldest block whose transactions have been indexed. txIndexTailKey = []byte("TransactionIndexTail") @@ -125,8 +129,10 @@ var ( StateHistoryIndexPrefix = []byte("m") // The global prefix of state history index data StateHistoryAccountMetadataPrefix = []byte("ma") // StateHistoryAccountMetadataPrefix + account address hash => account metadata StateHistoryStorageMetadataPrefix = []byte("ms") // StateHistoryStorageMetadataPrefix + account address hash + storage slot hash => slot metadata + TrienodeHistoryMetadataPrefix = []byte("mt") // TrienodeHistoryMetadataPrefix + account address hash + trienode path => trienode metadata StateHistoryAccountBlockPrefix = []byte("mba") // StateHistoryAccountBlockPrefix + account address hash + blockID => account block StateHistoryStorageBlockPrefix = []byte("mbs") // StateHistoryStorageBlockPrefix + account address hash + storage slot hash + blockID => slot block + TrienodeHistoryBlockPrefix = []byte("mbt") // TrienodeHistoryBlockPrefix + account address hash + trienode path + blockID => trienode block // VerklePrefix is the database prefix for Verkle trie data, which includes: // (a) Trie nodes @@ -395,27 +401,34 @@ func storageHistoryIndexKey(addressHash common.Hash, storageHash common.Hash) [] return out } +// trienodeHistoryIndexKey = TrienodeHistoryMetadataPrefix + addressHash + trienode path +func trienodeHistoryIndexKey(addressHash common.Hash, path []byte) []byte { + totalLen := len(TrienodeHistoryMetadataPrefix) + common.HashLength + len(path) + out := make([]byte, totalLen) + + off := 0 + off += copy(out[off:], TrienodeHistoryMetadataPrefix) + off += copy(out[off:], addressHash.Bytes()) + copy(out[off:], path) + + return out +} + // accountHistoryIndexBlockKey = StateHistoryAccountBlockPrefix + addressHash + blockID func accountHistoryIndexBlockKey(addressHash common.Hash, blockID uint32) []byte { - var buf4 [4]byte - binary.BigEndian.PutUint32(buf4[:], blockID) - totalLen := len(StateHistoryAccountBlockPrefix) + common.HashLength + 4 out := make([]byte, totalLen) off := 0 off += copy(out[off:], StateHistoryAccountBlockPrefix) off += copy(out[off:], addressHash.Bytes()) - copy(out[off:], buf4[:]) + binary.BigEndian.PutUint32(out[off:], blockID) return out } // storageHistoryIndexBlockKey = StateHistoryStorageBlockPrefix + addressHash + storageHash + blockID func storageHistoryIndexBlockKey(addressHash common.Hash, storageHash common.Hash, blockID uint32) []byte { - var buf4 [4]byte - binary.BigEndian.PutUint32(buf4[:], blockID) - totalLen := len(StateHistoryStorageBlockPrefix) + 2*common.HashLength + 4 out := make([]byte, totalLen) @@ -423,7 +436,21 @@ func storageHistoryIndexBlockKey(addressHash common.Hash, storageHash common.Has off += copy(out[off:], StateHistoryStorageBlockPrefix) off += copy(out[off:], addressHash.Bytes()) off += copy(out[off:], storageHash.Bytes()) - copy(out[off:], buf4[:]) + binary.BigEndian.PutUint32(out[off:], blockID) + + return out +} + +// trienodeHistoryIndexBlockKey = TrienodeHistoryBlockPrefix + addressHash + trienode path + blockID +func trienodeHistoryIndexBlockKey(addressHash common.Hash, path []byte, blockID uint32) []byte { + totalLen := len(TrienodeHistoryBlockPrefix) + common.HashLength + len(path) + 4 + out := make([]byte, totalLen) + + off := 0 + off += copy(out[off:], TrienodeHistoryBlockPrefix) + off += copy(out[off:], addressHash.Bytes()) + off += copy(out[off:], path) + binary.BigEndian.PutUint32(out[off:], blockID) return out } diff --git a/triedb/pathdb/database.go b/triedb/pathdb/database.go index 546d2e0301..9fc65de277 100644 --- a/triedb/pathdb/database.go +++ b/triedb/pathdb/database.go @@ -232,7 +232,7 @@ func (db *Database) repairHistory() error { // Purge all state history indexing data first batch := db.diskdb.NewBatch() rawdb.DeleteStateHistoryIndexMetadata(batch) - rawdb.DeleteStateHistoryIndex(batch) + rawdb.DeleteStateHistoryIndexes(batch) if err := batch.Write(); err != nil { log.Crit("Failed to purge state history index", "err", err) } @@ -426,7 +426,7 @@ func (db *Database) Enable(root common.Hash) error { // Purge all state history indexing data first batch.Reset() rawdb.DeleteStateHistoryIndexMetadata(batch) - rawdb.DeleteStateHistoryIndex(batch) + rawdb.DeleteStateHistoryIndexes(batch) if err := batch.Write(); err != nil { return err } diff --git a/triedb/pathdb/history.go b/triedb/pathdb/history.go index 81b843d9f1..d78999f218 100644 --- a/triedb/pathdb/history.go +++ b/triedb/pathdb/history.go @@ -32,6 +32,9 @@ type historyType uint8 const ( // typeStateHistory indicates history data related to account or storage changes. typeStateHistory historyType = 0 + + // typeTrienodeHistory indicates history data related to trie node changes. + typeTrienodeHistory historyType = 1 ) // String returns the string format representation. @@ -39,6 +42,8 @@ func (h historyType) String() string { switch h { case typeStateHistory: return "state" + case typeTrienodeHistory: + return "trienode" default: return fmt.Sprintf("unknown type: %d", h) } @@ -48,8 +53,9 @@ func (h historyType) String() string { type elementType uint8 const ( - typeAccount elementType = 0 // represents the account data - typeStorage elementType = 1 // represents the storage slot data + typeAccount elementType = 0 // represents the account data + typeStorage elementType = 1 // represents the storage slot data + typeTrienode elementType = 2 // represents the trie node data ) // String returns the string format representation. @@ -59,6 +65,8 @@ func (e elementType) String() string { return "account" case typeStorage: return "storage" + case typeTrienode: + return "trienode" default: return fmt.Sprintf("unknown element type: %d", e) } @@ -69,11 +77,14 @@ func toHistoryType(typ elementType) historyType { if typ == typeAccount || typ == typeStorage { return typeStateHistory } + if typ == typeTrienode { + return typeTrienodeHistory + } panic(fmt.Sprintf("unknown element type %v", typ)) } // stateIdent represents the identifier of a state element, which can be -// an account or a storage slot. +// an account, a storage slot or a trienode. type stateIdent struct { typ elementType @@ -91,6 +102,12 @@ type stateIdent struct { // // This field is null if the identifier refers to an account or a trie node. storageHash common.Hash + + // The trie node path within the trie. + // + // This field is null if the identifier refers to an account or a storage slot. + // String type is chosen to make stateIdent comparable. + path string } // String returns the string format state identifier. @@ -98,7 +115,10 @@ func (ident stateIdent) String() string { if ident.typ == typeAccount { return ident.addressHash.Hex() } - return ident.addressHash.Hex() + ident.storageHash.Hex() + if ident.typ == typeStorage { + return ident.addressHash.Hex() + ident.storageHash.Hex() + } + return ident.addressHash.Hex() + ident.path } // newAccountIdent constructs a state identifier for an account. @@ -120,8 +140,18 @@ func newStorageIdent(addressHash common.Hash, storageHash common.Hash) stateIden } } -// stateIdentQuery is the extension of stateIdent by adding the account address -// and raw storage key. +// newTrienodeIdent constructs a state identifier for a trie node. +// The address denotes the address hash of the associated account; +// the path denotes the path of the node within the trie; +func newTrienodeIdent(addressHash common.Hash, path string) stateIdent { + return stateIdent{ + typ: typeTrienode, + addressHash: addressHash, + path: path, + } +} + +// stateIdentQuery is the extension of stateIdent by adding the raw storage key. type stateIdentQuery struct { stateIdent @@ -150,8 +180,19 @@ func newStorageIdentQuery(address common.Address, addressHash common.Hash, stora } } -// history defines the interface of historical data, implemented by stateHistory -// and trienodeHistory (in the near future). +// newTrienodeIdentQuery constructs a state identifier for a trie node. +// the addressHash denotes the address hash of the associated account; +// the path denotes the path of the node within the trie; +// +// nolint:unused +func newTrienodeIdentQuery(addrHash common.Hash, path []byte) stateIdentQuery { + return stateIdentQuery{ + stateIdent: newTrienodeIdent(addrHash, string(path)), + } +} + +// history defines the interface of historical data, shared by stateHistory +// and trienodeHistory. type history interface { // typ returns the historical data type held in the history. typ() historyType diff --git a/triedb/pathdb/history_index.go b/triedb/pathdb/history_index.go index 47cee9820d..5b4c91d7e6 100644 --- a/triedb/pathdb/history_index.go +++ b/triedb/pathdb/history_index.go @@ -376,6 +376,8 @@ func readStateIndex(ident stateIdent, db ethdb.KeyValueReader) []byte { return rawdb.ReadAccountHistoryIndex(db, ident.addressHash) case typeStorage: return rawdb.ReadStorageHistoryIndex(db, ident.addressHash, ident.storageHash) + case typeTrienode: + return rawdb.ReadTrienodeHistoryIndex(db, ident.addressHash, []byte(ident.path)) default: panic(fmt.Errorf("unknown type: %v", ident.typ)) } @@ -389,6 +391,8 @@ func writeStateIndex(ident stateIdent, db ethdb.KeyValueWriter, data []byte) { rawdb.WriteAccountHistoryIndex(db, ident.addressHash, data) case typeStorage: rawdb.WriteStorageHistoryIndex(db, ident.addressHash, ident.storageHash, data) + case typeTrienode: + rawdb.WriteTrienodeHistoryIndex(db, ident.addressHash, []byte(ident.path), data) default: panic(fmt.Errorf("unknown type: %v", ident.typ)) } @@ -402,6 +406,8 @@ func deleteStateIndex(ident stateIdent, db ethdb.KeyValueWriter) { rawdb.DeleteAccountHistoryIndex(db, ident.addressHash) case typeStorage: rawdb.DeleteStorageHistoryIndex(db, ident.addressHash, ident.storageHash) + case typeTrienode: + rawdb.DeleteTrienodeHistoryIndex(db, ident.addressHash, []byte(ident.path)) default: panic(fmt.Errorf("unknown type: %v", ident.typ)) } @@ -415,6 +421,8 @@ func readStateIndexBlock(ident stateIdent, db ethdb.KeyValueReader, id uint32) [ return rawdb.ReadAccountHistoryIndexBlock(db, ident.addressHash, id) case typeStorage: return rawdb.ReadStorageHistoryIndexBlock(db, ident.addressHash, ident.storageHash, id) + case typeTrienode: + return rawdb.ReadTrienodeHistoryIndexBlock(db, ident.addressHash, []byte(ident.path), id) default: panic(fmt.Errorf("unknown type: %v", ident.typ)) } @@ -428,6 +436,8 @@ func writeStateIndexBlock(ident stateIdent, db ethdb.KeyValueWriter, id uint32, rawdb.WriteAccountHistoryIndexBlock(db, ident.addressHash, id, data) case typeStorage: rawdb.WriteStorageHistoryIndexBlock(db, ident.addressHash, ident.storageHash, id, data) + case typeTrienode: + rawdb.WriteTrienodeHistoryIndexBlock(db, ident.addressHash, []byte(ident.path), id, data) default: panic(fmt.Errorf("unknown type: %v", ident.typ)) } @@ -441,6 +451,8 @@ func deleteStateIndexBlock(ident stateIdent, db ethdb.KeyValueWriter, id uint32) rawdb.DeleteAccountHistoryIndexBlock(db, ident.addressHash, id) case typeStorage: rawdb.DeleteStorageHistoryIndexBlock(db, ident.addressHash, ident.storageHash, id) + case typeTrienode: + rawdb.DeleteTrienodeHistoryIndexBlock(db, ident.addressHash, []byte(ident.path), id) default: panic(fmt.Errorf("unknown type: %v", ident.typ)) } diff --git a/triedb/pathdb/history_indexer.go b/triedb/pathdb/history_indexer.go index d618585929..368ff78d41 100644 --- a/triedb/pathdb/history_indexer.go +++ b/triedb/pathdb/history_indexer.go @@ -36,8 +36,10 @@ const ( // The batch size for reading state histories historyReadBatch = 1000 - stateIndexV0 = uint8(0) // initial version of state index structure - stateIndexVersion = stateIndexV0 // the current state index version + stateHistoryIndexV0 = uint8(0) // initial version of state index structure + stateHistoryIndexVersion = stateHistoryIndexV0 // the current state index version + trienodeHistoryIndexV0 = uint8(0) // initial version of trienode index structure + trienodeHistoryIndexVersion = trienodeHistoryIndexV0 // the current trienode index version ) // indexVersion returns the latest index version for the given history type. @@ -45,7 +47,9 @@ const ( func indexVersion(typ historyType) uint8 { switch typ { case typeStateHistory: - return stateIndexVersion + return stateHistoryIndexVersion + case typeTrienodeHistory: + return trienodeHistoryIndexVersion default: panic(fmt.Errorf("unknown history type: %d", typ)) } @@ -63,6 +67,8 @@ func loadIndexMetadata(db ethdb.KeyValueReader, typ historyType) *indexMetadata switch typ { case typeStateHistory: blob = rawdb.ReadStateHistoryIndexMetadata(db) + case typeTrienodeHistory: + blob = rawdb.ReadTrienodeHistoryIndexMetadata(db) default: panic(fmt.Errorf("unknown history type %d", typ)) } @@ -90,6 +96,8 @@ func storeIndexMetadata(db ethdb.KeyValueWriter, typ historyType, last uint64) { switch typ { case typeStateHistory: rawdb.WriteStateHistoryIndexMetadata(db, blob) + case typeTrienodeHistory: + rawdb.WriteTrienodeHistoryIndexMetadata(db, blob) default: panic(fmt.Errorf("unknown history type %d", typ)) } @@ -101,6 +109,8 @@ func deleteIndexMetadata(db ethdb.KeyValueWriter, typ historyType) { switch typ { case typeStateHistory: rawdb.DeleteStateHistoryIndexMetadata(db) + case typeTrienodeHistory: + rawdb.DeleteTrienodeHistoryIndexMetadata(db) default: panic(fmt.Errorf("unknown history type %d", typ)) } @@ -215,7 +225,11 @@ func (b *batchIndexer) finish(force bool) error { func indexSingle(historyID uint64, db ethdb.KeyValueStore, freezer ethdb.AncientReader, typ historyType) error { start := time.Now() defer func() { - indexHistoryTimer.UpdateSince(start) + if typ == typeStateHistory { + stateIndexHistoryTimer.UpdateSince(start) + } else if typ == typeTrienodeHistory { + trienodeIndexHistoryTimer.UpdateSince(start) + } }() metadata := loadIndexMetadata(db, typ) @@ -234,7 +248,7 @@ func indexSingle(historyID uint64, db ethdb.KeyValueStore, freezer ethdb.Ancient if typ == typeStateHistory { h, err = readStateHistory(freezer, historyID) } else { - // h, err = readTrienodeHistory(freezer, historyID) + h, err = readTrienodeHistory(freezer, historyID) } if err != nil { return err @@ -253,7 +267,11 @@ func indexSingle(historyID uint64, db ethdb.KeyValueStore, freezer ethdb.Ancient func unindexSingle(historyID uint64, db ethdb.KeyValueStore, freezer ethdb.AncientReader, typ historyType) error { start := time.Now() defer func() { - unindexHistoryTimer.UpdateSince(start) + if typ == typeStateHistory { + stateUnindexHistoryTimer.UpdateSince(start) + } else if typ == typeTrienodeHistory { + trienodeUnindexHistoryTimer.UpdateSince(start) + } }() metadata := loadIndexMetadata(db, typ) @@ -272,7 +290,7 @@ func unindexSingle(historyID uint64, db ethdb.KeyValueStore, freezer ethdb.Ancie if typ == typeStateHistory { h, err = readStateHistory(freezer, historyID) } else { - // h, err = readTrienodeHistory(freezer, historyID) + h, err = readTrienodeHistory(freezer, historyID) } if err != nil { return err @@ -546,13 +564,13 @@ func (i *indexIniter) index(done chan struct{}, interrupt *atomic.Int32, lastID return } } else { - // histories, err = readTrienodeHistories(i.freezer, current, count) - // if err != nil { - // // The history read might fall if the history is truncated from - // // head due to revert operation. - // i.log.Error("Failed to read history for indexing", "current", current, "count", count, "err", err) - // return - // } + histories, err = readTrienodeHistories(i.freezer, current, count) + if err != nil { + // The history read might fall if the history is truncated from + // head due to revert operation. + i.log.Error("Failed to read history for indexing", "current", current, "count", count, "err", err) + return + } } for _, h := range histories { if err := batch.process(h, current); err != nil { @@ -570,7 +588,7 @@ func (i *indexIniter) index(done chan struct{}, interrupt *atomic.Int32, lastID done = current - beginID ) eta := common.CalculateETA(done, left, time.Since(start)) - i.log.Info("Indexing state history", "processed", done, "left", left, "elapsed", common.PrettyDuration(time.Since(start)), "eta", common.PrettyDuration(eta)) + i.log.Info("Indexing history", "processed", done, "left", left, "elapsed", common.PrettyDuration(time.Since(start)), "eta", common.PrettyDuration(eta)) } } i.indexed.Store(current - 1) // update indexing progress @@ -657,6 +675,8 @@ func checkVersion(disk ethdb.KeyValueStore, typ historyType) { var blob []byte if typ == typeStateHistory { blob = rawdb.ReadStateHistoryIndexMetadata(disk) + } else if typ == typeTrienodeHistory { + blob = rawdb.ReadTrienodeHistoryIndexMetadata(disk) } else { panic(fmt.Errorf("unknown history type: %v", typ)) } @@ -666,24 +686,32 @@ func checkVersion(disk ethdb.KeyValueStore, typ historyType) { return } // Short circuit if the metadata is found and the version is matched + ver := stateHistoryIndexVersion + if typ == typeTrienodeHistory { + ver = trienodeHistoryIndexVersion + } var m indexMetadata err := rlp.DecodeBytes(blob, &m) - if err == nil && m.Version == stateIndexVersion { + if err == nil && m.Version == ver { return } // Version is not matched, prune the existing data and re-index from scratch + batch := disk.NewBatch() + if typ == typeStateHistory { + rawdb.DeleteStateHistoryIndexMetadata(batch) + rawdb.DeleteStateHistoryIndexes(batch) + } else { + rawdb.DeleteTrienodeHistoryIndexMetadata(batch) + rawdb.DeleteTrienodeHistoryIndexes(batch) + } + if err := batch.Write(); err != nil { + log.Crit("Failed to purge history index", "type", typ, "err", err) + } version := "unknown" if err == nil { version = fmt.Sprintf("%d", m.Version) } - - batch := disk.NewBatch() - rawdb.DeleteStateHistoryIndexMetadata(batch) - rawdb.DeleteStateHistoryIndex(batch) - if err := batch.Write(); err != nil { - log.Crit("Failed to purge state history index", "err", err) - } - log.Info("Cleaned up obsolete state history index", "version", version, "want", stateIndexVersion) + log.Info("Cleaned up obsolete history index", "type", typ, "version", version, "want", version) } // newHistoryIndexer constructs the history indexer and launches the background diff --git a/triedb/pathdb/history_state.go b/triedb/pathdb/history_state.go index 9d1e4dfb09..bc21915dba 100644 --- a/triedb/pathdb/history_state.go +++ b/triedb/pathdb/history_state.go @@ -605,9 +605,9 @@ func writeStateHistory(writer ethdb.AncientWriter, dl *diffLayer) error { if err := rawdb.WriteStateHistory(writer, dl.stateID(), history.meta.encode(), accountIndex, storageIndex, accountData, storageData); err != nil { return err } - historyDataBytesMeter.Mark(int64(dataSize)) - historyIndexBytesMeter.Mark(int64(indexSize)) - historyBuildTimeMeter.UpdateSince(start) + stateHistoryDataBytesMeter.Mark(int64(dataSize)) + stateHistoryIndexBytesMeter.Mark(int64(indexSize)) + stateHistoryBuildTimeMeter.UpdateSince(start) log.Debug("Stored state history", "id", dl.stateID(), "block", dl.block, "data", dataSize, "index", indexSize, "elapsed", common.PrettyDuration(time.Since(start))) return nil diff --git a/triedb/pathdb/history_state_test.go b/triedb/pathdb/history_state_test.go index 5718081566..4046fb9640 100644 --- a/triedb/pathdb/history_state_test.go +++ b/triedb/pathdb/history_state_test.go @@ -98,13 +98,13 @@ func testEncodeDecodeStateHistory(t *testing.T, rawStorageKey bool) { if !compareSet(dec.accounts, obj.accounts) { t.Fatal("account data is mismatched") } - if !compareStorages(dec.storages, obj.storages) { + if !compareMapSet(dec.storages, obj.storages) { t.Fatal("storage data is mismatched") } if !compareList(dec.accountList, obj.accountList) { t.Fatal("account list is mismatched") } - if !compareStorageList(dec.storageList, obj.storageList) { + if !compareMapList(dec.storageList, obj.storageList) { t.Fatal("storage list is mismatched") } } @@ -292,32 +292,32 @@ func compareList[k comparable](a, b []k) bool { return true } -func compareStorages(a, b map[common.Address]map[common.Hash][]byte) bool { +func compareMapSet[K1 comparable, K2 comparable](a, b map[K1]map[K2][]byte) bool { if len(a) != len(b) { return false } - for h, subA := range a { - subB, ok := b[h] + for key, subsetA := range a { + subsetB, ok := b[key] if !ok { return false } - if !compareSet(subA, subB) { + if !compareSet(subsetA, subsetB) { return false } } return true } -func compareStorageList(a, b map[common.Address][]common.Hash) bool { +func compareMapList[K comparable, V comparable](a, b map[K][]V) bool { if len(a) != len(b) { return false } - for h, la := range a { - lb, ok := b[h] + for key, listA := range a { + listB, ok := b[key] if !ok { return false } - if !compareList(la, lb) { + if !compareList(listA, listB) { return false } } diff --git a/triedb/pathdb/history_trienode.go b/triedb/pathdb/history_trienode.go new file mode 100644 index 0000000000..2a4459d4ad --- /dev/null +++ b/triedb/pathdb/history_trienode.go @@ -0,0 +1,730 @@ +// Copyright 2025 The go-ethereum Authors +// This file is part of the go-ethereum library. +// +// The go-ethereum library is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// The go-ethereum library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the go-ethereum library. If not, see . + +package pathdb + +import ( + "bytes" + "encoding/binary" + "fmt" + "iter" + "maps" + "math" + "slices" + "sort" + "time" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/rawdb" + "github.com/ethereum/go-ethereum/ethdb" + "github.com/ethereum/go-ethereum/log" +) + +// Each trie node history entry consists of three parts (stored in three freezer +// tables according): +// +// # Header +// The header records metadata, including: +// +// - the history version (1 byte) +// - the parent state root (32 bytes) +// - the current state root (32 bytes) +// - block number (8 bytes) +// +// - a lexicographically sorted list of trie IDs +// - the corresponding offsets into the key and value sections for each trie data chunk +// +// Although some fields (e.g., parent state root, block number) are duplicated +// between the state history and the trienode history, these two histories +// operate independently. To ensure each remains self-contained and self-descriptive, +// we have chosen to maintain these duplicate fields. +// +// # Key section +// The key section stores trie node keys (paths) in a compressed format. +// It also contains relative offsets into the value section for resolving +// the corresponding trie node data. Note that these offsets are relative +// to the data chunk for the trie; the chunk offset must be added to obtain +// the absolute position. +// +// # Value section +// The value section is a concatenated byte stream of all trie node data. +// Each trie node can be retrieved using the offset and length specified +// by its index entry. +// +// The header and key sections are sufficient for locating a trie node, +// while a partial read of the value section is enough to retrieve its data. + +// Header section: +// +// +----------+------------------+---------------------+---------------------+-------+------------------+---------------------+---------------------| +// | metadata | TrieID(32 bytes) | key offset(4 bytes) | val offset(4 bytes) | ... | TrieID(32 bytes) | key offset(4 bytes) | val offset(4 bytes) | +// +----------+------------------+---------------------+---------------------+-------+------------------+---------------------+---------------------| +// +// +// Key section: +// +// + restart point + restart point (depends on restart interval) +// / / +// +---------------+---------------+---------------+---------------+---------+ +// | node entry 1 | node entry 2 | ... | node entry n | trailer | +// +---------------+---------------+---------------+---------------+---------+ +// \ / +// +---- restart block ------+ +// +// node entry: +// +// +---- key len ----+ +// / \ +// +-------+---------+-----------+---------+-----------------------+-----------------+ +// | shared (varint) | not shared (varint) | value length (varlen) | key (varlen) | +// +-----------------+---------------------+-----------------------+-----------------+ +// +// trailer: +// +// +---- 4-bytes ----+ +---- 4-bytes ----+ +// / \ / \ +// +----------------------+------------------------+-----+--------------------------+ +// | restart_1 key offset | restart_1 value offset | ... | restart number (4-bytes) | +// +----------------------+------------------------+-----+--------------------------+ +// +// Note: Both the key offset and the value offset are relative to the start of +// the trie data chunk. To obtain the absolute offset, add the offset of the +// trie data chunk itself. +// +// Value section: +// +// +--------------+--------------+-------+---------------+ +// | node data 1 | node data 2 | ... | node data n | +// +--------------+--------------+-------+---------------+ +// +// NOTE: All fixed-length integer are big-endian. + +const ( + trienodeHistoryV0 = uint8(0) // initial version of node history structure + trienodeHistoryVersion = trienodeHistoryV0 // the default node history version + trienodeMetadataSize = 1 + 2*common.HashLength + 8 // the size of metadata in the history + trienodeTrieHeaderSize = 8 + common.HashLength // the size of a single trie header in history + trienodeDataBlockRestartLen = 16 // The restart interval length of trie node block +) + +// trienodeMetadata describes the meta data of trienode history. +type trienodeMetadata struct { + version uint8 // version tag of history object + parent common.Hash // prev-state root before the state transition + root common.Hash // post-state root after the state transition + block uint64 // associated block number +} + +// trienodeHistory represents a set of trie node changes resulting from a state +// transition across the main account trie and all associated storage tries. +type trienodeHistory struct { + meta *trienodeMetadata // Metadata of the history + owners []common.Hash // List of trie identifier sorted lexicographically + nodeList map[common.Hash][]string // Set of node paths sorted lexicographically + nodes map[common.Hash]map[string][]byte // Set of original value of trie nodes before state transition +} + +// newTrienodeHistory constructs a trienode history with the provided trie nodes. +func newTrienodeHistory(root common.Hash, parent common.Hash, block uint64, nodes map[common.Hash]map[string][]byte) *trienodeHistory { + nodeList := make(map[common.Hash][]string) + for owner, subset := range nodes { + keys := sort.StringSlice(slices.Collect(maps.Keys(subset))) + keys.Sort() + nodeList[owner] = keys + } + return &trienodeHistory{ + meta: &trienodeMetadata{ + version: trienodeHistoryVersion, + parent: parent, + root: root, + block: block, + }, + owners: slices.SortedFunc(maps.Keys(nodes), common.Hash.Cmp), + nodeList: nodeList, + nodes: nodes, + } +} + +// sharedLen returns the length of the common prefix shared by a and b. +func sharedLen(a, b []byte) int { + n := min(len(a), len(b)) + for i := 0; i < n; i++ { + if a[i] != b[i] { + return i + } + } + return n +} + +// typ implements the history interface, returning the historical data type held. +func (h *trienodeHistory) typ() historyType { + return typeTrienodeHistory +} + +// forEach implements the history interface, returning an iterator to traverse the +// state entries in the history. +func (h *trienodeHistory) forEach() iter.Seq[stateIdent] { + return func(yield func(stateIdent) bool) { + for _, owner := range h.owners { + for _, path := range h.nodeList[owner] { + if !yield(newTrienodeIdent(owner, path)) { + return + } + } + } + } +} + +// encode serializes the contained trie nodes into bytes. +func (h *trienodeHistory) encode() ([]byte, []byte, []byte, error) { + var ( + buf = make([]byte, 64) + headerSection bytes.Buffer + keySection bytes.Buffer + valueSection bytes.Buffer + ) + binary.Write(&headerSection, binary.BigEndian, h.meta.version) // 1 byte + headerSection.Write(h.meta.parent.Bytes()) // 32 bytes + headerSection.Write(h.meta.root.Bytes()) // 32 bytes + binary.Write(&headerSection, binary.BigEndian, h.meta.block) // 8 byte + + for _, owner := range h.owners { + // Fill the header section with offsets at key and value section + headerSection.Write(owner.Bytes()) // 32 bytes + binary.Write(&headerSection, binary.BigEndian, uint32(keySection.Len())) // 4 bytes + + // The offset to the value section is theoretically unnecessary, since the + // individual value offset is already tracked in the key section. However, + // we still keep it here for two reasons: + // - It's cheap to store (only 4 bytes for each trie). + // - It can be useful for decoding the trie data when key is not required (e.g., in hash mode). + binary.Write(&headerSection, binary.BigEndian, uint32(valueSection.Len())) // 4 bytes + + // Fill the key section with node index + var ( + prevKey []byte + restarts []uint32 + prefixLen int + + internalKeyOffset uint32 // key offset for the trie internally + internalValOffset uint32 // value offset for the trie internally + ) + for i, path := range h.nodeList[owner] { + key := []byte(path) + if i%trienodeDataBlockRestartLen == 0 { + restarts = append(restarts, internalKeyOffset) + restarts = append(restarts, internalValOffset) + prefixLen = 0 + } else { + prefixLen = sharedLen(prevKey, key) + } + value := h.nodes[owner][path] + + // key section + n := binary.PutUvarint(buf[0:], uint64(prefixLen)) // key length shared (varint) + n += binary.PutUvarint(buf[n:], uint64(len(key)-prefixLen)) // key length not shared (varint) + n += binary.PutUvarint(buf[n:], uint64(len(value))) // value length (varint) + + if _, err := keySection.Write(buf[:n]); err != nil { + return nil, nil, nil, err + } + // unshared key + if _, err := keySection.Write(key[prefixLen:]); err != nil { + return nil, nil, nil, err + } + n += len(key) - prefixLen + prevKey = key + + // value section + if _, err := valueSection.Write(value); err != nil { + return nil, nil, nil, err + } + internalKeyOffset += uint32(n) + internalValOffset += uint32(len(value)) + } + + // Encode trailer, the number of restart sections is len(restarts))/2, + // as we track the offsets of both key and value sections. + var trailer []byte + for _, number := range append(restarts, uint32(len(restarts))/2) { + binary.BigEndian.PutUint32(buf[:4], number) + trailer = append(trailer, buf[:4]...) + } + if _, err := keySection.Write(trailer); err != nil { + return nil, nil, nil, err + } + } + return headerSection.Bytes(), keySection.Bytes(), valueSection.Bytes(), nil +} + +// decodeHeader resolves the metadata from the header section. An error +// should be returned if the header section is corrupted. +func decodeHeader(data []byte) (*trienodeMetadata, []common.Hash, []uint32, []uint32, error) { + if len(data) < trienodeMetadataSize { + return nil, nil, nil, nil, fmt.Errorf("trienode history is too small, index size: %d", len(data)) + } + version := data[0] + if version != trienodeHistoryVersion { + return nil, nil, nil, nil, fmt.Errorf("unregonized trienode history version: %d", version) + } + parent := common.BytesToHash(data[1 : common.HashLength+1]) // 32 bytes + root := common.BytesToHash(data[common.HashLength+1 : common.HashLength*2+1]) // 32 bytes + block := binary.BigEndian.Uint64(data[common.HashLength*2+1 : trienodeMetadataSize]) // 8 bytes + + size := len(data) - trienodeMetadataSize + if size%trienodeTrieHeaderSize != 0 { + return nil, nil, nil, nil, fmt.Errorf("truncated trienode history data, size %d", len(data)) + } + count := size / trienodeTrieHeaderSize + + var ( + owners = make([]common.Hash, 0, count) + keyOffsets = make([]uint32, 0, count) + valOffsets = make([]uint32, 0, count) + ) + for i := 0; i < count; i++ { + n := trienodeMetadataSize + trienodeTrieHeaderSize*i + owner := common.BytesToHash(data[n : n+common.HashLength]) + if i != 0 && bytes.Compare(owner.Bytes(), owners[i-1].Bytes()) <= 0 { + return nil, nil, nil, nil, fmt.Errorf("trienode owners are out of order, prev: %v, cur: %v", owners[i-1], owner) + } + owners = append(owners, owner) + + // Decode the offset to the key section + keyOffset := binary.BigEndian.Uint32(data[n+common.HashLength : n+common.HashLength+4]) + if i != 0 && keyOffset <= keyOffsets[i-1] { + return nil, nil, nil, nil, fmt.Errorf("key offset is out of order, prev: %v, cur: %v", keyOffsets[i-1], keyOffset) + } + keyOffsets = append(keyOffsets, keyOffset) + + // Decode the offset into the value section. Note that identical value offsets + // are valid if the node values in the last trie chunk are all zero (e.g., after + // a trie deletion). + valOffset := binary.BigEndian.Uint32(data[n+common.HashLength+4 : n+common.HashLength+8]) + if i != 0 && valOffset < valOffsets[i-1] { + return nil, nil, nil, nil, fmt.Errorf("value offset is out of order, prev: %v, cur: %v", valOffsets[i-1], valOffset) + } + valOffsets = append(valOffsets, valOffset) + } + return &trienodeMetadata{ + version: version, + parent: parent, + root: root, + block: block, + }, owners, keyOffsets, valOffsets, nil +} + +func decodeSingle(keySection []byte, onValue func([]byte, int, int) error) ([]string, error) { + var ( + prevKey []byte + items int + keyOffsets []uint32 + valOffsets []uint32 + + keyOff int // the key offset within the single trie data + valOff int // the value offset within the single trie data + + keys []string + ) + // Decode the number of restart section + if len(keySection) < 4 { + return nil, fmt.Errorf("key section too short, size: %d", len(keySection)) + } + nRestarts := binary.BigEndian.Uint32(keySection[len(keySection)-4:]) + + if len(keySection) < int(8*nRestarts)+4 { + return nil, fmt.Errorf("key section too short, restarts: %d, size: %d", nRestarts, len(keySection)) + } + for i := 0; i < int(nRestarts); i++ { + o := len(keySection) - 4 - (int(nRestarts)-i)*8 + keyOffset := binary.BigEndian.Uint32(keySection[o : o+4]) + if i != 0 && keyOffset <= keyOffsets[i-1] { + return nil, fmt.Errorf("key offset is out of order, prev: %v, cur: %v", keyOffsets[i-1], keyOffset) + } + keyOffsets = append(keyOffsets, keyOffset) + + // Same value offset is allowed just in case all the trie nodes in the last + // section have zero-size value. + valOffset := binary.BigEndian.Uint32(keySection[o+4 : o+8]) + if i != 0 && valOffset < valOffsets[i-1] { + return nil, fmt.Errorf("value offset is out of order, prev: %v, cur: %v", valOffsets[i-1], valOffset) + } + valOffsets = append(valOffsets, valOffset) + } + keyLimit := len(keySection) - 4 - int(nRestarts)*8 + + // Decode data + for keyOff < keyLimit { + // Validate the key and value offsets within the single trie data chunk + if items%trienodeDataBlockRestartLen == 0 { + if keyOff != int(keyOffsets[items/trienodeDataBlockRestartLen]) { + return nil, fmt.Errorf("key offset is not matched, recorded: %d, want: %d", keyOffsets[items/trienodeDataBlockRestartLen], keyOff) + } + if valOff != int(valOffsets[items/trienodeDataBlockRestartLen]) { + return nil, fmt.Errorf("value offset is not matched, recorded: %d, want: %d", valOffsets[items/trienodeDataBlockRestartLen], valOff) + } + } + // Resolve the entry from key section + nShared, nn := binary.Uvarint(keySection[keyOff:]) // key length shared (varint) + keyOff += nn + nUnshared, nn := binary.Uvarint(keySection[keyOff:]) // key length not shared (varint) + keyOff += nn + nValue, nn := binary.Uvarint(keySection[keyOff:]) // value length (varint) + keyOff += nn + + // Resolve unshared key + if keyOff+int(nUnshared) > len(keySection) { + return nil, fmt.Errorf("key length too long, unshared key length: %d, off: %d, section size: %d", nUnshared, keyOff, len(keySection)) + } + unsharedKey := keySection[keyOff : keyOff+int(nUnshared)] + keyOff += int(nUnshared) + + // Assemble the full key + var key []byte + if items%trienodeDataBlockRestartLen == 0 { + if nShared != 0 { + return nil, fmt.Errorf("unexpected non-zero shared key prefix: %d", nShared) + } + key = unsharedKey + } else { + if int(nShared) > len(prevKey) { + return nil, fmt.Errorf("unexpected shared key prefix: %d, prefix key length: %d", nShared, len(prevKey)) + } + key = append([]byte{}, prevKey[:nShared]...) + key = append(key, unsharedKey...) + } + if items != 0 && bytes.Compare(prevKey, key) >= 0 { + return nil, fmt.Errorf("trienode paths are out of order, prev: %v, cur: %v", prevKey, key) + } + prevKey = key + + // Resolve value + if onValue != nil { + if err := onValue(key, valOff, valOff+int(nValue)); err != nil { + return nil, err + } + } + valOff += int(nValue) + + items++ + keys = append(keys, string(key)) + } + if keyOff != keyLimit { + return nil, fmt.Errorf("excessive key data after decoding, offset: %d, size: %d", keyOff, keyLimit) + } + return keys, nil +} + +func decodeSingleWithValue(keySection []byte, valueSection []byte) ([]string, map[string][]byte, error) { + var ( + offset int + nodes = make(map[string][]byte) + ) + paths, err := decodeSingle(keySection, func(key []byte, start int, limit int) error { + if start != offset { + return fmt.Errorf("gapped value section offset: %d, want: %d", start, offset) + } + // start == limit is allowed for zero-value trie node (e.g., non-existent node) + if start > limit { + return fmt.Errorf("invalid value offsets, start: %d, limit: %d", start, limit) + } + if start > len(valueSection) || limit > len(valueSection) { + return fmt.Errorf("value section out of range: start: %d, limit: %d, size: %d", start, limit, len(valueSection)) + } + nodes[string(key)] = valueSection[start:limit] + + offset = limit + return nil + }) + if err != nil { + return nil, nil, err + } + if offset != len(valueSection) { + return nil, nil, fmt.Errorf("excessive value data after decoding, offset: %d, size: %d", offset, len(valueSection)) + } + return paths, nodes, nil +} + +// decode deserializes the contained trie nodes from the provided bytes. +func (h *trienodeHistory) decode(header []byte, keySection []byte, valueSection []byte) error { + metadata, owners, keyOffsets, valueOffsets, err := decodeHeader(header) + if err != nil { + return err + } + h.meta = metadata + h.owners = owners + h.nodeList = make(map[common.Hash][]string) + h.nodes = make(map[common.Hash]map[string][]byte) + + for i := 0; i < len(owners); i++ { + // Resolve the boundary of key section + keyStart := keyOffsets[i] + keyLimit := len(keySection) + if i != len(owners)-1 { + keyLimit = int(keyOffsets[i+1]) + } + if int(keyStart) > len(keySection) || keyLimit > len(keySection) { + return fmt.Errorf("invalid key offsets: keyStart: %d, keyLimit: %d, size: %d", keyStart, keyLimit, len(keySection)) + } + + // Resolve the boundary of value section + valStart := valueOffsets[i] + valLimit := len(valueSection) + if i != len(owners)-1 { + valLimit = int(valueOffsets[i+1]) + } + if int(valStart) > len(valueSection) || valLimit > len(valueSection) { + return fmt.Errorf("invalid value offsets: valueStart: %d, valueLimit: %d, size: %d", valStart, valLimit, len(valueSection)) + } + + // Decode the key and values for this specific trie + paths, nodes, err := decodeSingleWithValue(keySection[keyStart:keyLimit], valueSection[valStart:valLimit]) + if err != nil { + return err + } + h.nodeList[owners[i]] = paths + h.nodes[owners[i]] = nodes + } + return nil +} + +type iRange struct { + start uint32 + limit uint32 +} + +// singleTrienodeHistoryReader provides read access to a single trie within the +// trienode history. It stores an offset to the trie's position in the history, +// along with a set of per-node offsets that can be resolved on demand. +type singleTrienodeHistoryReader struct { + id uint64 + reader ethdb.AncientReader + valueRange iRange // value range within the total value section + valueInternalOffsets map[string]iRange // value offset within the single trie data +} + +func newSingleTrienodeHistoryReader(id uint64, reader ethdb.AncientReader, keyRange iRange, valueRange iRange) (*singleTrienodeHistoryReader, error) { + // TODO(rjl493456442) partial freezer read should be supported + keyData, err := rawdb.ReadTrienodeHistoryKeySection(reader, id) + if err != nil { + return nil, err + } + keyStart := int(keyRange.start) + keyLimit := int(keyRange.limit) + if keyLimit == math.MaxUint32 { + keyLimit = len(keyData) + } + if len(keyData) < keyStart || len(keyData) < keyLimit { + return nil, fmt.Errorf("key section too short, start: %d, limit: %d, size: %d", keyStart, keyLimit, len(keyData)) + } + + valueOffsets := make(map[string]iRange) + _, err = decodeSingle(keyData[keyStart:keyLimit], func(key []byte, start int, limit int) error { + valueOffsets[string(key)] = iRange{ + start: uint32(start), + limit: uint32(limit), + } + return nil + }) + if err != nil { + return nil, err + } + return &singleTrienodeHistoryReader{ + id: id, + reader: reader, + valueRange: valueRange, + valueInternalOffsets: valueOffsets, + }, nil +} + +// read retrieves the trie node data with the provided node path. +func (sr *singleTrienodeHistoryReader) read(path string) ([]byte, error) { + offset, exists := sr.valueInternalOffsets[path] + if !exists { + return nil, fmt.Errorf("trienode %v not found", []byte(path)) + } + // TODO(rjl493456442) partial freezer read should be supported + valueData, err := rawdb.ReadTrienodeHistoryValueSection(sr.reader, sr.id) + if err != nil { + return nil, err + } + if len(valueData) < int(sr.valueRange.start) { + return nil, fmt.Errorf("value section too short, start: %d, size: %d", sr.valueRange.start, len(valueData)) + } + entryStart := sr.valueRange.start + offset.start + entryLimit := sr.valueRange.start + offset.limit + if len(valueData) < int(entryStart) || len(valueData) < int(entryLimit) { + return nil, fmt.Errorf("value section too short, start: %d, limit: %d, size: %d", entryStart, entryLimit, len(valueData)) + } + return valueData[int(entryStart):int(entryLimit)], nil +} + +// trienodeHistoryReader provides read access to node data in the trie node history. +// It resolves data from the underlying ancient store only when needed, minimizing +// I/O overhead. +type trienodeHistoryReader struct { + id uint64 // ID of the associated trienode history + reader ethdb.AncientReader // Database reader of ancient store + keyRanges map[common.Hash]iRange // Key ranges identifying trie chunks + valRanges map[common.Hash]iRange // Value ranges identifying trie chunks + iReaders map[common.Hash]*singleTrienodeHistoryReader // readers for each individual trie chunk +} + +// newTrienodeHistoryReader constructs the reader for specific trienode history. +func newTrienodeHistoryReader(id uint64, reader ethdb.AncientReader) (*trienodeHistoryReader, error) { + r := &trienodeHistoryReader{ + id: id, + reader: reader, + keyRanges: make(map[common.Hash]iRange), + valRanges: make(map[common.Hash]iRange), + iReaders: make(map[common.Hash]*singleTrienodeHistoryReader), + } + if err := r.decodeHeader(); err != nil { + return nil, err + } + return r, nil +} + +// decodeHeader decodes the header section of trienode history. +func (r *trienodeHistoryReader) decodeHeader() error { + header, err := rawdb.ReadTrienodeHistoryHeader(r.reader, r.id) + if err != nil { + return err + } + _, owners, keyOffsets, valOffsets, err := decodeHeader(header) + if err != nil { + return err + } + for i, owner := range owners { + // Decode the key range for this trie chunk + var keyLimit uint32 + if i == len(owners)-1 { + keyLimit = math.MaxUint32 + } else { + keyLimit = keyOffsets[i+1] + } + r.keyRanges[owner] = iRange{ + start: keyOffsets[i], + limit: keyLimit, + } + + // Decode the value range for this trie chunk + var valLimit uint32 + if i == len(owners)-1 { + valLimit = math.MaxUint32 + } else { + valLimit = valOffsets[i+1] + } + r.valRanges[owner] = iRange{ + start: valOffsets[i], + limit: valLimit, + } + } + return nil +} + +// read retrieves the trie node data with the provided TrieID and node path. +func (r *trienodeHistoryReader) read(owner common.Hash, path string) ([]byte, error) { + ir, ok := r.iReaders[owner] + if !ok { + keyRange, exists := r.keyRanges[owner] + if !exists { + return nil, fmt.Errorf("trie %x is unknown", owner) + } + valRange, exists := r.valRanges[owner] + if !exists { + return nil, fmt.Errorf("trie %x is unknown", owner) + } + var err error + ir, err = newSingleTrienodeHistoryReader(r.id, r.reader, keyRange, valRange) + if err != nil { + return nil, err + } + r.iReaders[owner] = ir + } + return ir.read(path) +} + +// writeTrienodeHistory persists the trienode history associated with the given diff layer. +// nolint:unused +func writeTrienodeHistory(writer ethdb.AncientWriter, dl *diffLayer) error { + start := time.Now() + h := newTrienodeHistory(dl.rootHash(), dl.parent.rootHash(), dl.block, dl.nodes.nodeOrigin) + header, keySection, valueSection, err := h.encode() + if err != nil { + return err + } + // Write history data into five freezer table respectively. + if err := rawdb.WriteTrienodeHistory(writer, dl.stateID(), header, keySection, valueSection); err != nil { + return err + } + trienodeHistoryDataBytesMeter.Mark(int64(len(valueSection))) + trienodeHistoryIndexBytesMeter.Mark(int64(len(header) + len(keySection))) + trienodeHistoryBuildTimeMeter.UpdateSince(start) + + log.Debug( + "Stored trienode history", "id", dl.stateID(), "block", dl.block, + "header", common.StorageSize(len(header)), + "keySection", common.StorageSize(len(keySection)), + "valueSection", common.StorageSize(len(valueSection)), + "elapsed", common.PrettyDuration(time.Since(start)), + ) + return nil +} + +// readTrienodeMetadata resolves the metadata of the specified trienode history. +// nolint:unused +func readTrienodeMetadata(reader ethdb.AncientReader, id uint64) (*trienodeMetadata, error) { + header, err := rawdb.ReadTrienodeHistoryHeader(reader, id) + if err != nil { + return nil, err + } + metadata, _, _, _, err := decodeHeader(header) + if err != nil { + return nil, err + } + return metadata, nil +} + +// readTrienodeHistory resolves a single trienode history object with specific id. +func readTrienodeHistory(reader ethdb.AncientReader, id uint64) (*trienodeHistory, error) { + header, keySection, valueSection, err := rawdb.ReadTrienodeHistory(reader, id) + if err != nil { + return nil, err + } + var h trienodeHistory + if err := h.decode(header, keySection, valueSection); err != nil { + return nil, err + } + return &h, nil +} + +// readTrienodeHistories resolves a list of trienode histories with the specific range. +func readTrienodeHistories(reader ethdb.AncientReader, start uint64, count uint64) ([]history, error) { + headers, keySections, valueSections, err := rawdb.ReadTrienodeHistoryList(reader, start, count) + if err != nil { + return nil, err + } + var res []history + for i, header := range headers { + var h trienodeHistory + if err := h.decode(header, keySections[i], valueSections[i]); err != nil { + return nil, err + } + res = append(res, &h) + } + return res, nil +} diff --git a/triedb/pathdb/history_trienode_test.go b/triedb/pathdb/history_trienode_test.go new file mode 100644 index 0000000000..d6b80f61f5 --- /dev/null +++ b/triedb/pathdb/history_trienode_test.go @@ -0,0 +1,736 @@ +// Copyright 2025 The go-ethereum Authors +// This file is part of the go-ethereum library. +// +// The go-ethereum library is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// The go-ethereum library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the go-ethereum library. If not, see . + +package pathdb + +import ( + "bytes" + "encoding/binary" + "math/rand" + "reflect" + "testing" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/rawdb" + "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/internal/testrand" +) + +// randomTrienodes generates a random trienode set. +func randomTrienodes(n int) (map[common.Hash]map[string][]byte, common.Hash) { + var ( + root common.Hash + nodes = make(map[common.Hash]map[string][]byte) + ) + for i := 0; i < n; i++ { + owner := testrand.Hash() + if i == 0 { + owner = common.Hash{} + } + nodes[owner] = make(map[string][]byte) + + for j := 0; j < 10; j++ { + path := testrand.Bytes(rand.Intn(10)) + for z := 0; z < len(path); z++ { + nodes[owner][string(path[:z])] = testrand.Bytes(rand.Intn(128)) + } + } + // zero-size trie node, representing it was non-existent before + for j := 0; j < 10; j++ { + path := testrand.Bytes(32) + nodes[owner][string(path)] = nil + } + // root node with zero-size path + rnode := testrand.Bytes(256) + nodes[owner][""] = rnode + if owner == (common.Hash{}) { + root = crypto.Keccak256Hash(rnode) + } + } + return nodes, root +} + +func makeTrienodeHistory() *trienodeHistory { + nodes, root := randomTrienodes(10) + return newTrienodeHistory(root, common.Hash{}, 1, nodes) +} + +func makeTrienodeHistories(n int) []*trienodeHistory { + var ( + parent common.Hash + result []*trienodeHistory + ) + for i := 0; i < n; i++ { + nodes, root := randomTrienodes(10) + result = append(result, newTrienodeHistory(root, parent, uint64(i+1), nodes)) + parent = root + } + return result +} + +func TestEncodeDecodeTrienodeHistory(t *testing.T) { + var ( + dec trienodeHistory + obj = makeTrienodeHistory() + ) + header, keySection, valueSection, err := obj.encode() + if err != nil { + t.Fatalf("Failed to encode trienode history: %v", err) + } + if err := dec.decode(header, keySection, valueSection); err != nil { + t.Fatalf("Failed to decode trienode history: %v", err) + } + + if !reflect.DeepEqual(obj.meta, dec.meta) { + t.Fatal("trienode metadata is mismatched") + } + if !compareList(dec.owners, obj.owners) { + t.Fatal("trie owner list is mismatched") + } + if !compareMapList(dec.nodeList, obj.nodeList) { + t.Fatal("trienode list is mismatched") + } + if !compareMapSet(dec.nodes, obj.nodes) { + t.Fatal("trienode content is mismatched") + } + + // Re-encode again, ensuring the encoded blob still match + header2, keySection2, valueSection2, err := dec.encode() + if err != nil { + t.Fatalf("Failed to encode trienode history: %v", err) + } + if !bytes.Equal(header, header2) { + t.Fatal("re-encoded header is mismatched") + } + if !bytes.Equal(keySection, keySection2) { + t.Fatal("re-encoded key section is mismatched") + } + if !bytes.Equal(valueSection, valueSection2) { + t.Fatal("re-encoded value section is mismatched") + } +} + +func TestTrienodeHistoryReader(t *testing.T) { + var ( + hs = makeTrienodeHistories(10) + freezer, _ = rawdb.NewTrienodeFreezer(t.TempDir(), false, false) + ) + defer freezer.Close() + + for i, h := range hs { + header, keySection, valueSection, _ := h.encode() + if err := rawdb.WriteTrienodeHistory(freezer, uint64(i+1), header, keySection, valueSection); err != nil { + t.Fatalf("Failed to write trienode history: %v", err) + } + } + for i, h := range hs { + tr, err := newTrienodeHistoryReader(uint64(i+1), freezer) + if err != nil { + t.Fatalf("Failed to construct the history reader: %v", err) + } + for _, owner := range h.owners { + nodes := h.nodes[owner] + for key, value := range nodes { + blob, err := tr.read(owner, key) + if err != nil { + t.Fatalf("Failed to read trienode history: %v", err) + } + if !bytes.Equal(blob, value) { + t.Fatalf("Unexpected trie node data, want: %v, got: %v", value, blob) + } + } + } + } + for i, h := range hs { + metadata, err := readTrienodeMetadata(freezer, uint64(i+1)) + if err != nil { + t.Fatalf("Failed to read trienode history metadata: %v", err) + } + if !reflect.DeepEqual(h.meta, metadata) { + t.Fatalf("Unexpected trienode metadata, want: %v, got: %v", h.meta, metadata) + } + } +} + +// TestEmptyTrienodeHistory tests encoding/decoding of empty trienode history +func TestEmptyTrienodeHistory(t *testing.T) { + h := newTrienodeHistory(common.Hash{}, common.Hash{}, 1, make(map[common.Hash]map[string][]byte)) + + // Test encoding empty history + header, keySection, valueSection, err := h.encode() + if err != nil { + t.Fatalf("Failed to encode empty trienode history: %v", err) + } + + // Verify sections are minimal but valid + if len(header) == 0 { + t.Fatal("Header should not be empty") + } + if len(keySection) != 0 { + t.Fatal("Key section should be empty for empty history") + } + if len(valueSection) != 0 { + t.Fatal("Value section should be empty for empty history") + } + + // Test decoding empty history + var decoded trienodeHistory + if err := decoded.decode(header, keySection, valueSection); err != nil { + t.Fatalf("Failed to decode empty trienode history: %v", err) + } + + if len(decoded.owners) != 0 { + t.Fatal("Decoded history should have no owners") + } + if len(decoded.nodeList) != 0 { + t.Fatal("Decoded history should have no node lists") + } + if len(decoded.nodes) != 0 { + t.Fatal("Decoded history should have no nodes") + } +} + +// TestSingleTrieHistory tests encoding/decoding of history with single trie +func TestSingleTrieHistory(t *testing.T) { + nodes := make(map[common.Hash]map[string][]byte) + owner := testrand.Hash() + nodes[owner] = make(map[string][]byte) + + // Add some nodes with various sizes + nodes[owner][""] = testrand.Bytes(32) // empty key + nodes[owner]["a"] = testrand.Bytes(1) // small value + nodes[owner]["bb"] = testrand.Bytes(100) // medium value + nodes[owner]["ccc"] = testrand.Bytes(1000) // large value + nodes[owner]["dddd"] = testrand.Bytes(0) // empty value + + h := newTrienodeHistory(common.Hash{}, common.Hash{}, 1, nodes) + testEncodeDecode(t, h) +} + +// TestMultipleTries tests multiple tries with different node counts +func TestMultipleTries(t *testing.T) { + nodes := make(map[common.Hash]map[string][]byte) + + // First trie with many small nodes + owner1 := testrand.Hash() + nodes[owner1] = make(map[string][]byte) + for i := 0; i < 100; i++ { + key := string(testrand.Bytes(rand.Intn(10))) + nodes[owner1][key] = testrand.Bytes(rand.Intn(50)) + } + + // Second trie with few large nodes + owner2 := testrand.Hash() + nodes[owner2] = make(map[string][]byte) + for i := 0; i < 5; i++ { + key := string(testrand.Bytes(rand.Intn(20))) + nodes[owner2][key] = testrand.Bytes(1000 + rand.Intn(1000)) + } + + // Third trie with nil values (zero-size nodes) + owner3 := testrand.Hash() + nodes[owner3] = make(map[string][]byte) + for i := 0; i < 10; i++ { + key := string(testrand.Bytes(rand.Intn(15))) + nodes[owner3][key] = nil + } + + h := newTrienodeHistory(common.Hash{}, common.Hash{}, 1, nodes) + testEncodeDecode(t, h) +} + +// TestLargeNodeValues tests encoding/decoding with very large node values +func TestLargeNodeValues(t *testing.T) { + nodes := make(map[common.Hash]map[string][]byte) + owner := testrand.Hash() + nodes[owner] = make(map[string][]byte) + + // Test with progressively larger values + sizes := []int{1024, 10 * 1024, 100 * 1024, 1024 * 1024} // 1KB, 10KB, 100KB, 1MB + for _, size := range sizes { + key := string(testrand.Bytes(10)) + nodes[owner][key] = testrand.Bytes(size) + + h := newTrienodeHistory(common.Hash{}, common.Hash{}, 1, nodes) + testEncodeDecode(t, h) + t.Logf("Successfully tested encoding/decoding with %dKB value", size/1024) + } +} + +// TestNilNodeValues tests encoding/decoding with nil (zero-length) node values +func TestNilNodeValues(t *testing.T) { + nodes := make(map[common.Hash]map[string][]byte) + owner := testrand.Hash() + nodes[owner] = make(map[string][]byte) + + // Mix of nil and non-nil values + nodes[owner]["nil"] = nil + nodes[owner]["data1"] = []byte("some data") + nodes[owner]["data2"] = []byte("more data") + + h := newTrienodeHistory(common.Hash{}, common.Hash{}, 1, nodes) + testEncodeDecode(t, h) + + // Verify nil values are preserved + _, ok := h.nodes[owner]["nil"] + if !ok { + t.Fatal("Nil value should be preserved") + } +} + +// TestCorruptedHeader tests error handling for corrupted header data +func TestCorruptedHeader(t *testing.T) { + h := makeTrienodeHistory() + header, keySection, valueSection, _ := h.encode() + + // Test corrupted version + corruptedHeader := make([]byte, len(header)) + copy(corruptedHeader, header) + corruptedHeader[0] = 0xFF // Invalid version + + var decoded trienodeHistory + if err := decoded.decode(corruptedHeader, keySection, valueSection); err == nil { + t.Fatal("Expected error for corrupted version") + } + + // Test truncated header + truncatedHeader := header[:len(header)-5] + if err := decoded.decode(truncatedHeader, keySection, valueSection); err == nil { + t.Fatal("Expected error for truncated header") + } + + // Test header with invalid trie header size + invalidHeader := make([]byte, len(header)) + copy(invalidHeader, header) + invalidHeader = invalidHeader[:trienodeMetadataSize+5] // Not divisible by trie header size + + if err := decoded.decode(invalidHeader, keySection, valueSection); err == nil { + t.Fatal("Expected error for invalid header size") + } +} + +// TestCorruptedKeySection tests error handling for corrupted key section data +func TestCorruptedKeySection(t *testing.T) { + h := makeTrienodeHistory() + header, keySection, valueSection, _ := h.encode() + + // Test empty key section when header indicates data + if len(keySection) > 0 { + var decoded trienodeHistory + if err := decoded.decode(header, []byte{}, valueSection); err == nil { + t.Fatal("Expected error for empty key section with non-empty header") + } + } + + // Test truncated key section + if len(keySection) > 10 { + truncatedKeySection := keySection[:len(keySection)-10] + var decoded trienodeHistory + if err := decoded.decode(header, truncatedKeySection, valueSection); err == nil { + t.Fatal("Expected error for truncated key section") + } + } + + // Test corrupted key section with invalid varint + corruptedKeySection := make([]byte, len(keySection)) + copy(corruptedKeySection, keySection) + if len(corruptedKeySection) > 5 { + corruptedKeySection[5] = 0xFF // Corrupt varint encoding + var decoded trienodeHistory + if err := decoded.decode(header, corruptedKeySection, valueSection); err == nil { + t.Fatal("Expected error for corrupted varint in key section") + } + } +} + +// TestCorruptedValueSection tests error handling for corrupted value section data +func TestCorruptedValueSection(t *testing.T) { + h := makeTrienodeHistory() + header, keySection, valueSection, _ := h.encode() + + // Test truncated value section + if len(valueSection) > 10 { + truncatedValueSection := valueSection[:len(valueSection)-10] + var decoded trienodeHistory + if err := decoded.decode(header, keySection, truncatedValueSection); err == nil { + t.Fatal("Expected error for truncated value section") + } + } + + // Test empty value section when key section indicates data exists + if len(valueSection) > 0 { + var decoded trienodeHistory + if err := decoded.decode(header, keySection, []byte{}); err == nil { + t.Fatal("Expected error for empty value section with non-empty key section") + } + } +} + +// TestInvalidOffsets tests error handling for invalid offsets in encoded data +func TestInvalidOffsets(t *testing.T) { + h := makeTrienodeHistory() + header, keySection, valueSection, _ := h.encode() + + // Corrupt key offset in header (make it larger than key section) + corruptedHeader := make([]byte, len(header)) + copy(corruptedHeader, header) + corruptedHeader[trienodeMetadataSize+common.HashLength] = 0xff + + var dec1 trienodeHistory + if err := dec1.decode(corruptedHeader, keySection, valueSection); err == nil { + t.Fatal("Expected error for invalid key offset") + } + + // Corrupt value offset in header (make it larger than value section) + corruptedHeader = make([]byte, len(header)) + copy(corruptedHeader, header) + corruptedHeader[trienodeMetadataSize+common.HashLength+4] = 0xff + + var dec2 trienodeHistory + if err := dec2.decode(corruptedHeader, keySection, valueSection); err == nil { + t.Fatal("Expected error for invalid value offset") + } +} + +// TestTrienodeHistoryReaderNonExistentPath tests reading non-existent paths +func TestTrienodeHistoryReaderNonExistentPath(t *testing.T) { + var ( + h = makeTrienodeHistory() + freezer, _ = rawdb.NewTrienodeFreezer(t.TempDir(), false, false) + ) + defer freezer.Close() + + header, keySection, valueSection, _ := h.encode() + if err := rawdb.WriteTrienodeHistory(freezer, 1, header, keySection, valueSection); err != nil { + t.Fatalf("Failed to write trienode history: %v", err) + } + + tr, err := newTrienodeHistoryReader(1, freezer) + if err != nil { + t.Fatalf("Failed to construct history reader: %v", err) + } + + // Try to read a non-existent path + _, err = tr.read(testrand.Hash(), "nonexistent") + if err == nil { + t.Fatal("Expected error for non-existent trie owner") + } + + // Try to read from existing owner but non-existent path + owner := h.owners[0] + _, err = tr.read(owner, "nonexistent-path") + if err == nil { + t.Fatal("Expected error for non-existent path") + } +} + +// TestTrienodeHistoryReaderNilValues tests reading nil (zero-length) values +func TestTrienodeHistoryReaderNilValues(t *testing.T) { + nodes := make(map[common.Hash]map[string][]byte) + owner := testrand.Hash() + nodes[owner] = make(map[string][]byte) + + // Add some nil values + nodes[owner]["nil1"] = nil + nodes[owner]["nil2"] = nil + nodes[owner]["data1"] = []byte("some data") + + h := newTrienodeHistory(common.Hash{}, common.Hash{}, 1, nodes) + + var freezer, _ = rawdb.NewTrienodeFreezer(t.TempDir(), false, false) + defer freezer.Close() + + header, keySection, valueSection, _ := h.encode() + if err := rawdb.WriteTrienodeHistory(freezer, 1, header, keySection, valueSection); err != nil { + t.Fatalf("Failed to write trienode history: %v", err) + } + + tr, err := newTrienodeHistoryReader(1, freezer) + if err != nil { + t.Fatalf("Failed to construct history reader: %v", err) + } + + // Test reading nil values + data1, err := tr.read(owner, "nil1") + if err != nil { + t.Fatalf("Failed to read nil value: %v", err) + } + if len(data1) != 0 { + t.Fatal("Expected nil data for nil value") + } + + data2, err := tr.read(owner, "nil2") + if err != nil { + t.Fatalf("Failed to read nil value: %v", err) + } + if len(data2) != 0 { + t.Fatal("Expected nil data for nil value") + } + + // Test reading non-nil value + data3, err := tr.read(owner, "data1") + if err != nil { + t.Fatalf("Failed to read non-nil value: %v", err) + } + if !bytes.Equal(data3, []byte("some data")) { + t.Fatal("Data mismatch for non-nil value") + } +} + +// TestTrienodeHistoryReaderNilKey tests reading nil (zero-length) key +func TestTrienodeHistoryReaderNilKey(t *testing.T) { + nodes := make(map[common.Hash]map[string][]byte) + owner := testrand.Hash() + nodes[owner] = make(map[string][]byte) + + // Add some nil values + nodes[owner][""] = []byte("some data") + nodes[owner]["data1"] = []byte("some data") + + h := newTrienodeHistory(common.Hash{}, common.Hash{}, 1, nodes) + + var freezer, _ = rawdb.NewTrienodeFreezer(t.TempDir(), false, false) + defer freezer.Close() + + header, keySection, valueSection, _ := h.encode() + if err := rawdb.WriteTrienodeHistory(freezer, 1, header, keySection, valueSection); err != nil { + t.Fatalf("Failed to write trienode history: %v", err) + } + + tr, err := newTrienodeHistoryReader(1, freezer) + if err != nil { + t.Fatalf("Failed to construct history reader: %v", err) + } + + // Test reading nil values + data1, err := tr.read(owner, "") + if err != nil { + t.Fatalf("Failed to read nil value: %v", err) + } + if !bytes.Equal(data1, []byte("some data")) { + t.Fatal("Data mismatch for nil key") + } + + // Test reading non-nil value + data2, err := tr.read(owner, "data1") + if err != nil { + t.Fatalf("Failed to read non-nil value: %v", err) + } + if !bytes.Equal(data2, []byte("some data")) { + t.Fatal("Data mismatch for non-nil key") + } +} + +// TestTrienodeHistoryReaderIterator tests the iterator functionality +func TestTrienodeHistoryReaderIterator(t *testing.T) { + h := makeTrienodeHistory() + + // Count expected entries + expectedCount := 0 + expectedNodes := make(map[stateIdent]bool) + for owner, nodeList := range h.nodeList { + expectedCount += len(nodeList) + for _, node := range nodeList { + expectedNodes[stateIdent{ + typ: typeTrienode, + addressHash: owner, + path: node, + }] = true + } + } + + // Test the iterator + actualCount := 0 + for x := range h.forEach() { + _ = x + actualCount++ + } + if actualCount != expectedCount { + t.Fatalf("Iterator count mismatch: expected %d, got %d", expectedCount, actualCount) + } + + // Test that iterator yields expected state identifiers + seen := make(map[stateIdent]bool) + for ident := range h.forEach() { + if ident.typ != typeTrienode { + t.Fatal("Iterator should only yield trienode history identifiers") + } + key := stateIdent{typ: ident.typ, addressHash: ident.addressHash, path: ident.path} + if seen[key] { + t.Fatal("Iterator yielded duplicate identifier") + } + seen[key] = true + + if !expectedNodes[key] { + t.Fatalf("Unexpected yielded identifier %v", key) + } + } +} + +// TestSharedLen tests the sharedLen helper function +func TestSharedLen(t *testing.T) { + tests := []struct { + a, b []byte + expected int + }{ + // Empty strings + {[]byte(""), []byte(""), 0}, + // One empty string + {[]byte(""), []byte("abc"), 0}, + {[]byte("abc"), []byte(""), 0}, + // No common prefix + {[]byte("abc"), []byte("def"), 0}, + // Partial common prefix + {[]byte("abc"), []byte("abx"), 2}, + {[]byte("prefix"), []byte("pref"), 4}, + // Complete common prefix (shorter first) + {[]byte("ab"), []byte("abcd"), 2}, + // Complete common prefix (longer first) + {[]byte("abcd"), []byte("ab"), 2}, + // Identical strings + {[]byte("identical"), []byte("identical"), 9}, + // Binary data + {[]byte{0x00, 0x01, 0x02}, []byte{0x00, 0x01, 0x03}, 2}, + // Large strings + {bytes.Repeat([]byte("a"), 1000), bytes.Repeat([]byte("a"), 1000), 1000}, + {bytes.Repeat([]byte("a"), 1000), append(bytes.Repeat([]byte("a"), 999), []byte("b")...), 999}, + } + + for i, test := range tests { + result := sharedLen(test.a, test.b) + if result != test.expected { + t.Errorf("Test %d: sharedLen(%q, %q) = %d, expected %d", + i, test.a, test.b, result, test.expected) + } + // Test commutativity + resultReverse := sharedLen(test.b, test.a) + if result != resultReverse { + t.Errorf("Test %d: sharedLen is not commutative: sharedLen(a,b)=%d, sharedLen(b,a)=%d", + i, result, resultReverse) + } + } +} + +// TestDecodeHeaderCorruptedData tests decodeHeader with corrupted data +func TestDecodeHeaderCorruptedData(t *testing.T) { + // Create valid header data first + h := makeTrienodeHistory() + header, _, _, _ := h.encode() + + // Test with empty header + _, _, _, _, err := decodeHeader([]byte{}) + if err == nil { + t.Fatal("Expected error for empty header") + } + + // Test with invalid version + corruptedVersion := make([]byte, len(header)) + copy(corruptedVersion, header) + corruptedVersion[0] = 0xFF + _, _, _, _, err = decodeHeader(corruptedVersion) + if err == nil { + t.Fatal("Expected error for invalid version") + } + + // Test with truncated header (not divisible by trie header size) + truncated := header[:trienodeMetadataSize+5] + _, _, _, _, err = decodeHeader(truncated) + if err == nil { + t.Fatal("Expected error for truncated header") + } + + // Test with unordered trie owners + unordered := make([]byte, len(header)) + copy(unordered, header) + + // Swap two owner hashes to make them unordered + hash1Start := trienodeMetadataSize + hash2Start := trienodeMetadataSize + trienodeTrieHeaderSize + hash1 := unordered[hash1Start : hash1Start+common.HashLength] + hash2 := unordered[hash2Start : hash2Start+common.HashLength] + + // Only swap if they would be out of order + copy(unordered[hash1Start:hash1Start+common.HashLength], hash2) + copy(unordered[hash2Start:hash2Start+common.HashLength], hash1) + + _, _, _, _, err = decodeHeader(unordered) + if err == nil { + t.Fatal("Expected error for unordered trie owners") + } +} + +// TestDecodeSingleCorruptedData tests decodeSingle with corrupted data +func TestDecodeSingleCorruptedData(t *testing.T) { + h := makeTrienodeHistory() + _, keySection, _, _ := h.encode() + + // Test with empty key section + _, err := decodeSingle([]byte{}, nil) + if err == nil { + t.Fatal("Expected error for empty key section") + } + + // Test with key section too small for trailer + if len(keySection) > 0 { + _, err := decodeSingle(keySection[:3], nil) // Less than 4 bytes for trailer + if err == nil { + t.Fatal("Expected error for key section too small for trailer") + } + } + + // Test with corrupted varint in key section + corrupted := make([]byte, len(keySection)) + copy(corrupted, keySection) + corrupted[5] = 0xFF // Corrupt varint + _, err = decodeSingle(corrupted, nil) + if err == nil { + t.Fatal("Expected error for corrupted varint") + } + + // Test with corrupted trailer (invalid restart count) + corrupted = make([]byte, len(keySection)) + copy(corrupted, keySection) + // Set restart count to something too large + binary.BigEndian.PutUint32(corrupted[len(corrupted)-4:], 10000) + _, err = decodeSingle(corrupted, nil) + if err == nil { + t.Fatal("Expected error for invalid restart count") + } +} + +// Helper function to test encode/decode cycle +func testEncodeDecode(t *testing.T, h *trienodeHistory) { + header, keySection, valueSection, err := h.encode() + if err != nil { + t.Fatalf("Failed to encode trienode history: %v", err) + } + + var decoded trienodeHistory + if err := decoded.decode(header, keySection, valueSection); err != nil { + t.Fatalf("Failed to decode trienode history: %v", err) + } + + // Compare the decoded history with original + if !compareList(decoded.owners, h.owners) { + t.Fatal("Trie owner list mismatch") + } + if !compareMapList(decoded.nodeList, h.nodeList) { + t.Fatal("Trienode list mismatch") + } + if !compareMapSet(decoded.nodes, h.nodes) { + t.Fatal("Trienode content mismatch") + } +} diff --git a/triedb/pathdb/metrics.go b/triedb/pathdb/metrics.go index 779f9d813f..31c40053fc 100644 --- a/triedb/pathdb/metrics.go +++ b/triedb/pathdb/metrics.go @@ -69,12 +69,21 @@ var ( gcStorageMeter = metrics.NewRegisteredMeter("pathdb/gc/storage/count", nil) gcStorageBytesMeter = metrics.NewRegisteredMeter("pathdb/gc/storage/bytes", nil) - historyBuildTimeMeter = metrics.NewRegisteredResettingTimer("pathdb/history/time", nil) - historyDataBytesMeter = metrics.NewRegisteredMeter("pathdb/history/bytes/data", nil) - historyIndexBytesMeter = metrics.NewRegisteredMeter("pathdb/history/bytes/index", nil) + stateHistoryBuildTimeMeter = metrics.NewRegisteredResettingTimer("pathdb/history/state/time", nil) + stateHistoryDataBytesMeter = metrics.NewRegisteredMeter("pathdb/history/state/bytes/data", nil) + stateHistoryIndexBytesMeter = metrics.NewRegisteredMeter("pathdb/history/state/bytes/index", nil) - indexHistoryTimer = metrics.NewRegisteredResettingTimer("pathdb/history/index/time", nil) - unindexHistoryTimer = metrics.NewRegisteredResettingTimer("pathdb/history/unindex/time", nil) + //nolint:unused + trienodeHistoryBuildTimeMeter = metrics.NewRegisteredResettingTimer("pathdb/history/trienode/time", nil) + //nolint:unused + trienodeHistoryDataBytesMeter = metrics.NewRegisteredMeter("pathdb/history/trienode/bytes/data", nil) + //nolint:unused + trienodeHistoryIndexBytesMeter = metrics.NewRegisteredMeter("pathdb/history/trienode/bytes/index", nil) + + stateIndexHistoryTimer = metrics.NewRegisteredResettingTimer("pathdb/history/state/index/time", nil) + stateUnindexHistoryTimer = metrics.NewRegisteredResettingTimer("pathdb/history/state/unindex/time", nil) + trienodeIndexHistoryTimer = metrics.NewRegisteredResettingTimer("pathdb/history/trienode/index/time", nil) + trienodeUnindexHistoryTimer = metrics.NewRegisteredResettingTimer("pathdb/history/trienode/unindex/time", nil) lookupAddLayerTimer = metrics.NewRegisteredResettingTimer("pathdb/lookup/add/time", nil) lookupRemoveLayerTimer = metrics.NewRegisteredResettingTimer("pathdb/lookup/remove/time", nil) From 659342a52300d9cd8218face5528a91e7434a8fb Mon Sep 17 00:00:00 2001 From: 10gic Date: Fri, 10 Oct 2025 17:47:33 +0800 Subject: [PATCH 23/23] ethclient: add SubscribeTransactionReceipts (#32869) Add `SubscribeTransactionReceipts` for ethclient. This is a complement to https://github.com/ethereum/go-ethereum/pull/32697. --- eth/filters/api.go | 24 ++++++++++++++++++------ ethclient/ethclient.go | 9 +++++++++ interfaces.go | 12 ++++++++++++ 3 files changed, 39 insertions(+), 6 deletions(-) diff --git a/eth/filters/api.go b/eth/filters/api.go index 9f9209aea7..a3ed00f33b 100644 --- a/eth/filters/api.go +++ b/eth/filters/api.go @@ -299,15 +299,27 @@ func (api *FilterAPI) Logs(ctx context.Context, crit FilterCriteria) (*rpc.Subsc return rpcSub, nil } -// TransactionReceiptsFilter defines criteria for transaction receipts subscription. -// If TransactionHashes is nil or empty, receipts for all transactions included in new blocks will be delivered. -// Otherwise, only receipts for the specified transactions will be delivered. -type TransactionReceiptsFilter struct { - TransactionHashes []common.Hash `json:"transactionHashes,omitempty"` +// TransactionReceiptsQuery defines criteria for transaction receipts subscription. +// Same as ethereum.TransactionReceiptsQuery but with UnmarshalJSON() method. +type TransactionReceiptsQuery ethereum.TransactionReceiptsQuery + +// UnmarshalJSON sets *args fields with given data. +func (args *TransactionReceiptsQuery) UnmarshalJSON(data []byte) error { + type input struct { + TransactionHashes []common.Hash `json:"transactionHashes"` + } + + var raw input + if err := json.Unmarshal(data, &raw); err != nil { + return err + } + + args.TransactionHashes = raw.TransactionHashes + return nil } // TransactionReceipts creates a subscription that fires transaction receipts when transactions are included in blocks. -func (api *FilterAPI) TransactionReceipts(ctx context.Context, filter *TransactionReceiptsFilter) (*rpc.Subscription, error) { +func (api *FilterAPI) TransactionReceipts(ctx context.Context, filter *TransactionReceiptsQuery) (*rpc.Subscription, error) { notifier, supported := rpc.NotifierFromContext(ctx) if !supported { return &rpc.Subscription{}, rpc.ErrNotificationsUnsupported diff --git a/ethclient/ethclient.go b/ethclient/ethclient.go index 1195929f7d..8b26f5b3ca 100644 --- a/ethclient/ethclient.go +++ b/ethclient/ethclient.go @@ -350,6 +350,15 @@ func (ec *Client) TransactionReceipt(ctx context.Context, txHash common.Hash) (* return r, err } +// SubscribeTransactionReceipts subscribes to notifications about transaction receipts. +func (ec *Client) SubscribeTransactionReceipts(ctx context.Context, q *ethereum.TransactionReceiptsQuery, ch chan<- []*types.Receipt) (ethereum.Subscription, error) { + sub, err := ec.c.EthSubscribe(ctx, ch, "transactionReceipts", q) + if err != nil { + return nil, err + } + return sub, nil +} + // SyncProgress retrieves the current progress of the sync algorithm. If there's // no sync currently running, it returns nil. func (ec *Client) SyncProgress(ctx context.Context) (*ethereum.SyncProgress, error) { diff --git a/interfaces.go b/interfaces.go index be5b970851..2828af1cc9 100644 --- a/interfaces.go +++ b/interfaces.go @@ -62,6 +62,13 @@ type ChainReader interface { SubscribeNewHead(ctx context.Context, ch chan<- *types.Header) (Subscription, error) } +// TransactionReceiptsQuery defines criteria for transaction receipts subscription. +// If TransactionHashes is empty, receipts for all transactions included in new blocks will be delivered. +// Otherwise, only receipts for the specified transactions will be delivered. +type TransactionReceiptsQuery struct { + TransactionHashes []common.Hash +} + // TransactionReader provides access to past transactions and their receipts. // Implementations may impose arbitrary restrictions on the transactions and receipts that // can be retrieved. Historic transactions may not be available. @@ -81,6 +88,11 @@ type TransactionReader interface { // transaction may not be included in the current canonical chain even if a receipt // exists. TransactionReceipt(ctx context.Context, txHash common.Hash) (*types.Receipt, error) + // SubscribeTransactionReceipts subscribes to notifications about transaction receipts. + // The receipts are delivered in batches when transactions are included in blocks. + // If q is nil or has empty TransactionHashes, all receipts from new blocks will be delivered. + // Otherwise, only receipts for the specified transaction hashes will be delivered. + SubscribeTransactionReceipts(ctx context.Context, q *TransactionReceiptsQuery, ch chan<- []*types.Receipt) (Subscription, error) } // ChainStateReader wraps access to the state trie of the canonical blockchain. Note that