From d14d4d2af07090a22f8651366146e3f17e09ed6b Mon Sep 17 00:00:00 2001 From: ericxtheodore Date: Wed, 30 Jul 2025 10:39:03 +0800 Subject: [PATCH 01/57] core/state: improve PrettyPrint function (#32293) --- core/state/access_list.go | 5 +---- core/state/transient_storage.go | 13 ++++--------- 2 files changed, 5 insertions(+), 13 deletions(-) diff --git a/core/state/access_list.go b/core/state/access_list.go index a58c2b20ea..e3f1738864 100644 --- a/core/state/access_list.go +++ b/core/state/access_list.go @@ -145,10 +145,7 @@ func (al *accessList) Equal(other *accessList) bool { // PrettyPrint prints the contents of the access list in a human-readable form func (al *accessList) PrettyPrint() string { out := new(strings.Builder) - var sortedAddrs []common.Address - for addr := range al.addresses { - sortedAddrs = append(sortedAddrs, addr) - } + sortedAddrs := slices.Collect(maps.Keys(al.addresses)) slices.SortFunc(sortedAddrs, common.Address.Cmp) for _, addr := range sortedAddrs { idx := al.addresses[addr] diff --git a/core/state/transient_storage.go b/core/state/transient_storage.go index e63db39eba..3bb4955425 100644 --- a/core/state/transient_storage.go +++ b/core/state/transient_storage.go @@ -18,6 +18,7 @@ package state import ( "fmt" + "maps" "slices" "strings" @@ -70,19 +71,13 @@ func (t transientStorage) Copy() transientStorage { // PrettyPrint prints the contents of the access list in a human-readable form func (t transientStorage) PrettyPrint() string { out := new(strings.Builder) - var sortedAddrs []common.Address - for addr := range t { - sortedAddrs = append(sortedAddrs, addr) - slices.SortFunc(sortedAddrs, common.Address.Cmp) - } + sortedAddrs := slices.Collect(maps.Keys(t)) + slices.SortFunc(sortedAddrs, common.Address.Cmp) for _, addr := range sortedAddrs { fmt.Fprintf(out, "%#x:", addr) - var sortedKeys []common.Hash storage := t[addr] - for key := range storage { - sortedKeys = append(sortedKeys, key) - } + sortedKeys := slices.Collect(maps.Keys(storage)) slices.SortFunc(sortedKeys, common.Hash.Cmp) for _, key := range sortedKeys { fmt.Fprintf(out, " %X : %X\n", key, storage[key]) From 2d95ba7d15879677cb451bbaa5d2c34c2b4f323d Mon Sep 17 00:00:00 2001 From: Daniel Katzan <108216499+dkatzan@users.noreply.github.com> Date: Thu, 31 Jul 2025 08:34:17 +0700 Subject: [PATCH 02/57] core/types: expose sigHash as Hash for SetCodeAuthorization (#32298) --- core/types/tx_setcode.go | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/core/types/tx_setcode.go b/core/types/tx_setcode.go index b8e38ef1f7..f2281d4ae7 100644 --- a/core/types/tx_setcode.go +++ b/core/types/tx_setcode.go @@ -89,7 +89,7 @@ type authorizationMarshaling struct { // SignSetCode creates a signed the SetCode authorization. func SignSetCode(prv *ecdsa.PrivateKey, auth SetCodeAuthorization) (SetCodeAuthorization, error) { - sighash := auth.sigHash() + sighash := auth.SigHash() sig, err := crypto.Sign(sighash[:], prv) if err != nil { return SetCodeAuthorization{}, err @@ -105,7 +105,8 @@ func SignSetCode(prv *ecdsa.PrivateKey, auth SetCodeAuthorization) (SetCodeAutho }, nil } -func (a *SetCodeAuthorization) sigHash() common.Hash { +// SigHash returns the hash of SetCodeAuthorization for signing. +func (a *SetCodeAuthorization) SigHash() common.Hash { return prefixedRlpHash(0x05, []any{ a.ChainID, a.Address, @@ -115,7 +116,7 @@ func (a *SetCodeAuthorization) sigHash() common.Hash { // Authority recovers the the authorizing account of an authorization. func (a *SetCodeAuthorization) Authority() (common.Address, error) { - sighash := a.sigHash() + sighash := a.SigHash() if !crypto.ValidateSignatureValues(a.V, a.R.ToBig(), a.S.ToBig(), true) { return common.Address{}, ErrInvalidSig } From 0814d991aba32ce4f2a0253f1c06c2da22788408 Mon Sep 17 00:00:00 2001 From: cui Date: Thu, 31 Jul 2025 09:48:31 +0800 Subject: [PATCH 03/57] common/hexutil: replace customized bit sizer with bit.Uintsize (#32304) --- common/hexutil/hexutil.go | 5 ++--- common/hexutil/json_test.go | 3 ++- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/common/hexutil/hexutil.go b/common/hexutil/hexutil.go index d3201850a8..d6b6b867f2 100644 --- a/common/hexutil/hexutil.go +++ b/common/hexutil/hexutil.go @@ -34,11 +34,10 @@ import ( "encoding/hex" "fmt" "math/big" + "math/bits" "strconv" ) -const uintBits = 32 << (uint64(^uint(0)) >> 63) - // Errors var ( ErrEmptyString = &decError{"empty hex string"} @@ -48,7 +47,7 @@ var ( ErrEmptyNumber = &decError{"hex string \"0x\""} ErrLeadingZero = &decError{"hex number with leading zero digits"} ErrUint64Range = &decError{"hex number > 64 bits"} - ErrUintRange = &decError{fmt.Sprintf("hex number > %d bits", uintBits)} + ErrUintRange = &decError{fmt.Sprintf("hex number > %d bits", bits.UintSize)} ErrBig256Range = &decError{"hex number > 256 bits"} ) diff --git a/common/hexutil/json_test.go b/common/hexutil/json_test.go index 7cca300951..a014438458 100644 --- a/common/hexutil/json_test.go +++ b/common/hexutil/json_test.go @@ -22,6 +22,7 @@ import ( "encoding/json" "errors" "math/big" + "math/bits" "testing" "github.com/holiman/uint256" @@ -384,7 +385,7 @@ func TestUnmarshalUint(t *testing.T) { for _, test := range unmarshalUintTests { var v Uint err := json.Unmarshal([]byte(test.input), &v) - if uintBits == 32 && test.wantErr32bit != nil { + if bits.UintSize == 32 && test.wantErr32bit != nil { checkError(t, test.input, err, test.wantErr32bit) continue } From 4d9d72806ccd09ce0d452abf77dc77aa3413b972 Mon Sep 17 00:00:00 2001 From: cui Date: Thu, 31 Jul 2025 09:53:31 +0800 Subject: [PATCH 04/57] accounts/abi: precompile regex (#32301) --- accounts/abi/abigen/bind.go | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/accounts/abi/abigen/bind.go b/accounts/abi/abigen/bind.go index 56e5e214de..08624b04ba 100644 --- a/accounts/abi/abigen/bind.go +++ b/accounts/abi/abigen/bind.go @@ -33,6 +33,10 @@ import ( "github.com/ethereum/go-ethereum/log" ) +var ( + intRegex = regexp.MustCompile(`(u)?int([0-9]*)`) +) + func isKeyWord(arg string) bool { switch arg { case "break": @@ -299,7 +303,7 @@ func bindBasicType(kind abi.Type) string { case abi.AddressTy: return "common.Address" case abi.IntTy, abi.UintTy: - parts := regexp.MustCompile(`(u)?int([0-9]*)`).FindStringSubmatch(kind.String()) + parts := intRegex.FindStringSubmatch(kind.String()) switch parts[2] { case "8", "16", "32", "64": return fmt.Sprintf("%sint%s", parts[1], parts[2]) From d4a3bf1b23e3972fb82e085c0e29fe2c4647ed5c Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Thu, 31 Jul 2025 12:13:36 +0200 Subject: [PATCH 05/57] cmd/devp2p/internal/v4test: add test for ENRRequest (#32303) This adds a cross-client protocol test for a recently discovered bug in Nethermind. --- cmd/devp2p/internal/v4test/discv4tests.go | 32 +++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/cmd/devp2p/internal/v4test/discv4tests.go b/cmd/devp2p/internal/v4test/discv4tests.go index 963df6cdbc..de97d7a276 100644 --- a/cmd/devp2p/internal/v4test/discv4tests.go +++ b/cmd/devp2p/internal/v4test/discv4tests.go @@ -27,6 +27,7 @@ import ( "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/internal/utesting" "github.com/ethereum/go-ethereum/p2p/discover/v4wire" + "github.com/ethereum/go-ethereum/p2p/enode" ) const ( @@ -501,6 +502,36 @@ func FindnodeAmplificationWrongIP(t *utesting.T) { } } +func ENRRequest(t *utesting.T) { + t.Log(`This test sends an ENRRequest packet and expects a response containing a valid ENR.`) + + te := newTestEnv(Remote, Listen1, Listen2) + defer te.close() + bond(t, te) + + req := &v4wire.ENRRequest{Expiration: futureExpiration()} + hash := te.send(te.l1, req) + + response, _, err := te.read(te.l1) + if err != nil { + t.Fatal("read error:", err) + } + enrResp, ok := response.(*v4wire.ENRResponse) + if !ok { + t.Fatalf("expected ENRResponse packet, got %T", response) + } + if !bytes.Equal(enrResp.ReplyTok, hash) { + t.Errorf("wrong hash in response packet: got %x, want %x", enrResp.ReplyTok, hash) + } + node, err := enode.New(enode.ValidSchemes, &enrResp.Record) + if err != nil { + t.Errorf("invalid record in response: %v", err) + } + if node.ID() != te.remote.ID() { + t.Errorf("wrong node ID in response: got %v, want %v", node.ID(), te.remote.ID()) + } +} + var AllTests = []utesting.Test{ {Name: "Ping/Basic", Fn: BasicPing}, {Name: "Ping/WrongTo", Fn: PingWrongTo}, @@ -510,6 +541,7 @@ var AllTests = []utesting.Test{ {Name: "Ping/PastExpiration", Fn: PingPastExpiration}, {Name: "Ping/WrongPacketType", Fn: WrongPacketType}, {Name: "Ping/BondThenPingWithWrongFrom", Fn: BondThenPingWithWrongFrom}, + {Name: "ENRRequest", Fn: ENRRequest}, {Name: "Findnode/WithoutEndpointProof", Fn: FindnodeWithoutEndpointProof}, {Name: "Findnode/BasicFindnode", Fn: BasicFindnode}, {Name: "Findnode/UnsolicitedNeighbors", Fn: UnsolicitedNeighbors}, From 23da91f73b83eb1d101889b2f773c6f0a80a8f15 Mon Sep 17 00:00:00 2001 From: rjl493456442 Date: Fri, 1 Aug 2025 10:23:23 +0800 Subject: [PATCH 06/57] trie: reduce the memory allocation in trie hashing (#31902) This pull request optimizes trie hashing by reducing memory allocation overhead. Specifically: - define a fullNodeEncoder pool to reuse encoders and avoid memory allocations. - simplify the encoding logic for shortNode and fullNode by getting rid of the Go interfaces. --- trie/hasher.go | 181 ++++++++++++++++++++++++---------------------- trie/iterator.go | 6 +- trie/node.go | 4 - trie/node_enc.go | 23 ++++-- trie/proof.go | 14 +--- trie/trie.go | 6 +- trie/trie_test.go | 1 - 7 files changed, 122 insertions(+), 113 deletions(-) diff --git a/trie/hasher.go b/trie/hasher.go index 16606808c9..a2a1f5b662 100644 --- a/trie/hasher.go +++ b/trie/hasher.go @@ -17,6 +17,8 @@ package trie import ( + "bytes" + "fmt" "sync" "github.com/ethereum/go-ethereum/crypto" @@ -54,7 +56,7 @@ func returnHasherToPool(h *hasher) { } // hash collapses a node down into a hash node. -func (h *hasher) hash(n node, force bool) node { +func (h *hasher) hash(n node, force bool) []byte { // Return the cached hash if it's available if hash, _ := n.cache(); hash != nil { return hash @@ -62,101 +64,110 @@ func (h *hasher) hash(n node, force bool) node { // Trie not processed yet, walk the children switch n := n.(type) { case *shortNode: - collapsed := h.hashShortNodeChildren(n) - hashed := h.shortnodeToHash(collapsed, force) - if hn, ok := hashed.(hashNode); ok { - n.flags.hash = hn - } else { - n.flags.hash = nil + enc := h.encodeShortNode(n) + if len(enc) < 32 && !force { + // Nodes smaller than 32 bytes are embedded directly in their parent. + // In such cases, return the raw encoded blob instead of the node hash. + // It's essential to deep-copy the node blob, as the underlying buffer + // of enc will be reused later. + buf := make([]byte, len(enc)) + copy(buf, enc) + return buf } - return hashed + hash := h.hashData(enc) + n.flags.hash = hash + return hash + case *fullNode: - collapsed := h.hashFullNodeChildren(n) - hashed := h.fullnodeToHash(collapsed, force) - if hn, ok := hashed.(hashNode); ok { - n.flags.hash = hn - } else { - n.flags.hash = nil + enc := h.encodeFullNode(n) + if len(enc) < 32 && !force { + // Nodes smaller than 32 bytes are embedded directly in their parent. + // In such cases, return the raw encoded blob instead of the node hash. + // It's essential to deep-copy the node blob, as the underlying buffer + // of enc will be reused later. + buf := make([]byte, len(enc)) + copy(buf, enc) + return buf } - return hashed - default: - // Value and hash nodes don't have children, so they're left as were + hash := h.hashData(enc) + n.flags.hash = hash + return hash + + case hashNode: + // hash nodes don't have children, so they're left as were return n - } -} -// hashShortNodeChildren returns a copy of the supplied shortNode, with its child -// being replaced by either the hash or an embedded node if the child is small. -func (h *hasher) hashShortNodeChildren(n *shortNode) *shortNode { - var collapsed shortNode - collapsed.Key = hexToCompact(n.Key) - switch n.Val.(type) { - case *fullNode, *shortNode: - collapsed.Val = h.hash(n.Val, false) default: - collapsed.Val = n.Val + panic(fmt.Errorf("unexpected node type, %T", n)) } - return &collapsed } -// hashFullNodeChildren returns a copy of the supplied fullNode, with its child -// being replaced by either the hash or an embedded node if the child is small. -func (h *hasher) hashFullNodeChildren(n *fullNode) *fullNode { - var children [17]node +// encodeShortNode encodes the provided shortNode into the bytes. Notably, the +// return slice must be deep-copied explicitly, otherwise the underlying slice +// will be reused later. +func (h *hasher) encodeShortNode(n *shortNode) []byte { + // Encode leaf node + if hasTerm(n.Key) { + var ln leafNodeEncoder + ln.Key = hexToCompact(n.Key) + ln.Val = n.Val.(valueNode) + ln.encode(h.encbuf) + return h.encodedBytes() + } + // Encode extension node + var en extNodeEncoder + en.Key = hexToCompact(n.Key) + en.Val = h.hash(n.Val, false) + en.encode(h.encbuf) + return h.encodedBytes() +} + +// fnEncoderPool is the pool for storing shared fullNode encoder to mitigate +// the significant memory allocation overhead. +var fnEncoderPool = sync.Pool{ + New: func() interface{} { + var enc fullnodeEncoder + return &enc + }, +} + +// encodeFullNode encodes the provided fullNode into the bytes. Notably, the +// return slice must be deep-copied explicitly, otherwise the underlying slice +// will be reused later. +func (h *hasher) encodeFullNode(n *fullNode) []byte { + fn := fnEncoderPool.Get().(*fullnodeEncoder) + fn.reset() + if h.parallel { var wg sync.WaitGroup for i := 0; i < 16; i++ { - if child := n.Children[i]; child != nil { - wg.Add(1) - go func(i int) { - hasher := newHasher(false) - children[i] = hasher.hash(child, false) - returnHasherToPool(hasher) - wg.Done() - }(i) - } else { - children[i] = nilValueNode + if n.Children[i] == nil { + continue } + wg.Add(1) + go func(i int) { + defer wg.Done() + + h := newHasher(false) + fn.Children[i] = h.hash(n.Children[i], false) + returnHasherToPool(h) + }(i) } wg.Wait() } else { for i := 0; i < 16; i++ { if child := n.Children[i]; child != nil { - children[i] = h.hash(child, false) - } else { - children[i] = nilValueNode + fn.Children[i] = h.hash(child, false) } } } if n.Children[16] != nil { - children[16] = n.Children[16] + fn.Children[16] = n.Children[16].(valueNode) } - return &fullNode{flags: nodeFlag{}, Children: children} -} + fn.encode(h.encbuf) + fnEncoderPool.Put(fn) -// shortNodeToHash computes the hash of the given shortNode. The shortNode must -// first be collapsed, with its key converted to compact form. If the RLP-encoded -// node data is smaller than 32 bytes, the node itself is returned. -func (h *hasher) shortnodeToHash(n *shortNode, force bool) node { - n.encode(h.encbuf) - enc := h.encodedBytes() - - if len(enc) < 32 && !force { - return n // Nodes smaller than 32 bytes are stored inside their parent - } - return h.hashData(enc) -} - -// fullnodeToHash computes the hash of the given fullNode. If the RLP-encoded -// node data is smaller than 32 bytes, the node itself is returned. -func (h *hasher) fullnodeToHash(n *fullNode, force bool) node { - n.encode(h.encbuf) - enc := h.encodedBytes() - - if len(enc) < 32 && !force { - return n // Nodes smaller than 32 bytes are stored inside their parent - } - return h.hashData(enc) + return h.encodedBytes() } // encodedBytes returns the result of the last encoding operation on h.encbuf. @@ -175,9 +186,10 @@ func (h *hasher) encodedBytes() []byte { return h.tmp } -// hashData hashes the provided data -func (h *hasher) hashData(data []byte) hashNode { - n := make(hashNode, 32) +// hashData hashes the provided data. It is safe to modify the returned slice after +// the function returns. +func (h *hasher) hashData(data []byte) []byte { + n := make([]byte, 32) h.sha.Reset() h.sha.Write(data) h.sha.Read(n) @@ -192,20 +204,17 @@ func (h *hasher) hashDataTo(dst, data []byte) { h.sha.Read(dst) } -// proofHash is used to construct trie proofs, and returns the 'collapsed' -// node (for later RLP encoding) as well as the hashed node -- unless the -// node is smaller than 32 bytes, in which case it will be returned as is. -// This method does not do anything on value- or hash-nodes. -func (h *hasher) proofHash(original node) (collapsed, hashed node) { +// proofHash is used to construct trie proofs, returning the rlp-encoded node blobs. +// Note, only resolved node (shortNode or fullNode) is expected for proofing. +// +// It is safe to modify the returned slice after the function returns. +func (h *hasher) proofHash(original node) []byte { switch n := original.(type) { case *shortNode: - sn := h.hashShortNodeChildren(n) - return sn, h.shortnodeToHash(sn, false) + return bytes.Clone(h.encodeShortNode(n)) case *fullNode: - fn := h.hashFullNodeChildren(n) - return fn, h.fullnodeToHash(fn, false) + return bytes.Clone(h.encodeFullNode(n)) default: - // Value and hash nodes don't have children, so they're left as were - return n, n + panic(fmt.Errorf("unexpected node type, %T", original)) } } diff --git a/trie/iterator.go b/trie/iterator.go index fa01611063..e6fedf2430 100644 --- a/trie/iterator.go +++ b/trie/iterator.go @@ -240,9 +240,9 @@ func (it *nodeIterator) LeafProof() [][]byte { for i, item := range it.stack[:len(it.stack)-1] { // Gather nodes that end up as hash nodes (or the root) - node, hashed := hasher.proofHash(item.node) - if _, ok := hashed.(hashNode); ok || i == 0 { - proofs = append(proofs, nodeToBytes(node)) + enc := hasher.proofHash(item.node) + if len(enc) >= 32 || i == 0 { + proofs = append(proofs, enc) } } return proofs diff --git a/trie/node.go b/trie/node.go index 96f077ebbb..74fac4fd4e 100644 --- a/trie/node.go +++ b/trie/node.go @@ -68,10 +68,6 @@ type ( } ) -// nilValueNode is used when collapsing internal trie nodes for hashing, since -// unset children need to serialize correctly. -var nilValueNode = valueNode(nil) - // EncodeRLP encodes a full node into the consensus RLP format. func (n *fullNode) EncodeRLP(w io.Writer) error { eb := rlp.NewEncoderBuffer(w) diff --git a/trie/node_enc.go b/trie/node_enc.go index c95587eeab..02b93ee6f3 100644 --- a/trie/node_enc.go +++ b/trie/node_enc.go @@ -42,18 +42,29 @@ func (n *fullNode) encode(w rlp.EncoderBuffer) { func (n *fullnodeEncoder) encode(w rlp.EncoderBuffer) { offset := w.List() - for _, c := range n.Children { - if c == nil { + for i, c := range n.Children { + if len(c) == 0 { w.Write(rlp.EmptyString) - } else if len(c) < 32 { - w.Write(c) // rawNode } else { - w.WriteBytes(c) // hashNode + // valueNode or hashNode + if i == 16 || len(c) >= 32 { + w.WriteBytes(c) + } else { + w.Write(c) // rawNode + } } } w.ListEnd(offset) } +func (n *fullnodeEncoder) reset() { + for i, c := range n.Children { + if len(c) != 0 { + n.Children[i] = n.Children[i][:0] + } + } +} + func (n *shortNode) encode(w rlp.EncoderBuffer) { offset := w.List() w.WriteBytes(n.Key) @@ -70,7 +81,7 @@ func (n *extNodeEncoder) encode(w rlp.EncoderBuffer) { w.WriteBytes(n.Key) if n.Val == nil { - w.Write(rlp.EmptyString) + w.Write(rlp.EmptyString) // theoretically impossible to happen } else if len(n.Val) < 32 { w.Write(n.Val) // rawNode } else { diff --git a/trie/proof.go b/trie/proof.go index 751d6f620f..53b7acc30c 100644 --- a/trie/proof.go +++ b/trie/proof.go @@ -22,6 +22,7 @@ import ( "fmt" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/log" ) @@ -85,16 +86,9 @@ func (t *Trie) Prove(key []byte, proofDb ethdb.KeyValueWriter) error { defer returnHasherToPool(hasher) for i, n := range nodes { - var hn node - n, hn = hasher.proofHash(n) - if hash, ok := hn.(hashNode); ok || i == 0 { - // If the node's database encoding is a hash (or is the - // root node), it becomes a proof element. - enc := nodeToBytes(n) - if !ok { - hash = hasher.hashData(enc) - } - proofDb.Put(hash, enc) + enc := hasher.proofHash(n) + if len(enc) >= 32 || i == 0 { + proofDb.Put(crypto.Keccak256(enc), enc) } } return nil diff --git a/trie/trie.go b/trie/trie.go index fdb4da9be4..222bf8b1f0 100644 --- a/trie/trie.go +++ b/trie/trie.go @@ -626,7 +626,7 @@ func (t *Trie) resolveAndTrack(n hashNode, prefix []byte) (node, error) { // Hash returns the root hash of the trie. It does not write to the // database and can be used even if the trie doesn't have one. func (t *Trie) Hash() common.Hash { - return common.BytesToHash(t.hashRoot().(hashNode)) + return common.BytesToHash(t.hashRoot()) } // Commit collects all dirty nodes in the trie and replaces them with the @@ -677,9 +677,9 @@ func (t *Trie) Commit(collectLeaf bool) (common.Hash, *trienode.NodeSet) { } // hashRoot calculates the root hash of the given trie -func (t *Trie) hashRoot() node { +func (t *Trie) hashRoot() []byte { if t.root == nil { - return hashNode(types.EmptyRootHash.Bytes()) + return types.EmptyRootHash.Bytes() } // If the number of changes is below 100, we let one thread handle it h := newHasher(t.unhashed >= 100) diff --git a/trie/trie_test.go b/trie/trie_test.go index b806ae6b0c..edd85677fe 100644 --- a/trie/trie_test.go +++ b/trie/trie_test.go @@ -863,7 +863,6 @@ func (s *spongeDb) Flush() { s.sponge.Write([]byte(key)) s.sponge.Write([]byte(s.values[key])) } - fmt.Println(len(s.keys)) } // spongeBatch is a dummy batch which immediately writes to the underlying spongedb From 17d65e9451111288d96f8fb6befb8544a94b6d50 Mon Sep 17 00:00:00 2001 From: lmittmann <3458786+lmittmann@users.noreply.github.com> Date: Fri, 1 Aug 2025 13:57:38 +0200 Subject: [PATCH 07/57] core/vm: add configurable jumpdest analysis cache (#32143) This adds a method on vm.EVM to set the jumpdest cache implementation. It can be used to maintain an analysis cache across VM invocations, to improve performance by skipping the analysis for already known contracts. --------- Co-authored-by: lmittmann Co-authored-by: Felix Lange --- core/vm/analysis_legacy.go | 20 +++++++------- core/vm/analysis_legacy_test.go | 2 +- core/vm/contract.go | 16 +++++------ core/vm/evm.go | 12 ++++++--- core/vm/jumpdests.go | 47 +++++++++++++++++++++++++++++++++ 5 files changed, 74 insertions(+), 23 deletions(-) create mode 100644 core/vm/jumpdests.go diff --git a/core/vm/analysis_legacy.go b/core/vm/analysis_legacy.go index 38af9084ac..a445e2048e 100644 --- a/core/vm/analysis_legacy.go +++ b/core/vm/analysis_legacy.go @@ -25,16 +25,16 @@ const ( set7BitsMask = uint16(0b111_1111) ) -// bitvec is a bit vector which maps bytes in a program. +// BitVec is a bit vector which maps bytes in a program. // An unset bit means the byte is an opcode, a set bit means // it's data (i.e. argument of PUSHxx). -type bitvec []byte +type BitVec []byte -func (bits bitvec) set1(pos uint64) { +func (bits BitVec) set1(pos uint64) { bits[pos/8] |= 1 << (pos % 8) } -func (bits bitvec) setN(flag uint16, pos uint64) { +func (bits BitVec) setN(flag uint16, pos uint64) { a := flag << (pos % 8) bits[pos/8] |= byte(a) if b := byte(a >> 8); b != 0 { @@ -42,13 +42,13 @@ func (bits bitvec) setN(flag uint16, pos uint64) { } } -func (bits bitvec) set8(pos uint64) { +func (bits BitVec) set8(pos uint64) { a := byte(0xFF << (pos % 8)) bits[pos/8] |= a bits[pos/8+1] = ^a } -func (bits bitvec) set16(pos uint64) { +func (bits BitVec) set16(pos uint64) { a := byte(0xFF << (pos % 8)) bits[pos/8] |= a bits[pos/8+1] = 0xFF @@ -56,23 +56,23 @@ func (bits bitvec) set16(pos uint64) { } // codeSegment checks if the position is in a code segment. -func (bits *bitvec) codeSegment(pos uint64) bool { +func (bits *BitVec) codeSegment(pos uint64) bool { return (((*bits)[pos/8] >> (pos % 8)) & 1) == 0 } // codeBitmap collects data locations in code. -func codeBitmap(code []byte) bitvec { +func codeBitmap(code []byte) BitVec { // The bitmap is 4 bytes longer than necessary, in case the code // ends with a PUSH32, the algorithm will set bits on the // bitvector outside the bounds of the actual code. - bits := make(bitvec, len(code)/8+1+4) + bits := make(BitVec, len(code)/8+1+4) return codeBitmapInternal(code, bits) } // codeBitmapInternal is the internal implementation of codeBitmap. // It exists for the purpose of being able to run benchmark tests // without dynamic allocations affecting the results. -func codeBitmapInternal(code, bits bitvec) bitvec { +func codeBitmapInternal(code, bits BitVec) BitVec { for pc := uint64(0); pc < uint64(len(code)); { op := OpCode(code[pc]) pc++ diff --git a/core/vm/analysis_legacy_test.go b/core/vm/analysis_legacy_test.go index 471d2b4ffb..f84a4abc92 100644 --- a/core/vm/analysis_legacy_test.go +++ b/core/vm/analysis_legacy_test.go @@ -90,7 +90,7 @@ func BenchmarkJumpdestOpAnalysis(bench *testing.B) { for i := range code { code[i] = byte(op) } - bits := make(bitvec, len(code)/8+1+4) + bits := make(BitVec, len(code)/8+1+4) b.ResetTimer() for i := 0; i < b.N; i++ { clear(bits) diff --git a/core/vm/contract.go b/core/vm/contract.go index 0eaa91d959..165ca833f8 100644 --- a/core/vm/contract.go +++ b/core/vm/contract.go @@ -31,8 +31,8 @@ type Contract struct { caller common.Address address common.Address - jumpdests map[common.Hash]bitvec // Aggregated result of JUMPDEST analysis. - analysis bitvec // Locally cached result of JUMPDEST analysis + jumpDests JumpDestCache // Aggregated result of JUMPDEST analysis. + analysis BitVec // Locally cached result of JUMPDEST analysis Code []byte CodeHash common.Hash @@ -47,15 +47,15 @@ type Contract struct { } // NewContract returns a new contract environment for the execution of EVM. -func NewContract(caller common.Address, address common.Address, value *uint256.Int, gas uint64, jumpDests map[common.Hash]bitvec) *Contract { - // Initialize the jump analysis map if it's nil, mostly for tests +func NewContract(caller common.Address, address common.Address, value *uint256.Int, gas uint64, jumpDests JumpDestCache) *Contract { + // Initialize the jump analysis cache if it's nil, mostly for tests if jumpDests == nil { - jumpDests = make(map[common.Hash]bitvec) + jumpDests = newMapJumpDests() } return &Contract{ caller: caller, address: address, - jumpdests: jumpDests, + jumpDests: jumpDests, Gas: gas, value: value, } @@ -87,12 +87,12 @@ func (c *Contract) isCode(udest uint64) bool { // contracts ( not temporary initcode), we store the analysis in a map if c.CodeHash != (common.Hash{}) { // Does parent context have the analysis? - analysis, exist := c.jumpdests[c.CodeHash] + analysis, exist := c.jumpDests.Load(c.CodeHash) if !exist { // Do the analysis and save in parent context // We do not need to store it in c.analysis analysis = codeBitmap(c.Code) - c.jumpdests[c.CodeHash] = analysis + c.jumpDests.Store(c.CodeHash, analysis) } // Also stash it in current contract for faster access c.analysis = analysis diff --git a/core/vm/evm.go b/core/vm/evm.go index b45a434545..143b7e08a2 100644 --- a/core/vm/evm.go +++ b/core/vm/evm.go @@ -122,9 +122,8 @@ type EVM struct { // precompiles holds the precompiled contracts for the current epoch precompiles map[common.Address]PrecompiledContract - // jumpDests is the aggregated result of JUMPDEST analysis made through - // the life cycle of EVM. - jumpDests map[common.Hash]bitvec + // jumpDests stores results of JUMPDEST analysis. + jumpDests JumpDestCache } // NewEVM constructs an EVM instance with the supplied block context, state @@ -138,7 +137,7 @@ func NewEVM(blockCtx BlockContext, statedb StateDB, chainConfig *params.ChainCon Config: config, chainConfig: chainConfig, chainRules: chainConfig.Rules(blockCtx.BlockNumber, blockCtx.Random != nil, blockCtx.Time), - jumpDests: make(map[common.Hash]bitvec), + jumpDests: newMapJumpDests(), } evm.precompiles = activePrecompiledContracts(evm.chainRules) evm.interpreter = NewEVMInterpreter(evm) @@ -152,6 +151,11 @@ func (evm *EVM) SetPrecompiles(precompiles PrecompiledContracts) { evm.precompiles = precompiles } +// SetJumpDestCache configures the analysis cache. +func (evm *EVM) SetJumpDestCache(jumpDests JumpDestCache) { + evm.jumpDests = jumpDests +} + // SetTxContext resets the EVM with a new transaction context. // This is not threadsafe and should only be done very cautiously. func (evm *EVM) SetTxContext(txCtx TxContext) { diff --git a/core/vm/jumpdests.go b/core/vm/jumpdests.go new file mode 100644 index 0000000000..1a30c1943f --- /dev/null +++ b/core/vm/jumpdests.go @@ -0,0 +1,47 @@ +// Copyright 2024 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 vm + +import "github.com/ethereum/go-ethereum/common" + +// JumpDestCache represents the cache of jumpdest analysis results. +type JumpDestCache interface { + // Load retrieves the cached jumpdest analysis for the given code hash. + // Returns the BitVec and true if found, or nil and false if not cached. + Load(codeHash common.Hash) (BitVec, bool) + + // Store saves the jumpdest analysis for the given code hash. + Store(codeHash common.Hash, vec BitVec) +} + +// mapJumpDests is the default implementation of JumpDests using a map. +// This implementation is not thread-safe and is meant to be used per EVM instance. +type mapJumpDests map[common.Hash]BitVec + +// newMapJumpDests creates a new map-based JumpDests implementation. +func newMapJumpDests() JumpDestCache { + return make(mapJumpDests) +} + +func (j mapJumpDests) Load(codeHash common.Hash) (BitVec, bool) { + vec, ok := j[codeHash] + return vec, ok +} + +func (j mapJumpDests) Store(codeHash common.Hash, vec BitVec) { + j[codeHash] = vec +} From 9c58810e717e7c48dff31ebc7280ba47675597a6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1s=20Andr=C3=B3il?= Date: Fri, 1 Aug 2025 14:00:00 +0200 Subject: [PATCH 08/57] eth: fix typos and outdated comments (#32324) --- eth/ethconfig/config.go | 2 +- eth/filters/filter.go | 1 - eth/filters/filter_system.go | 2 +- 3 files changed, 2 insertions(+), 3 deletions(-) diff --git a/eth/ethconfig/config.go b/eth/ethconfig/config.go index 7eba6a6408..82c3c500a7 100644 --- a/eth/ethconfig/config.go +++ b/eth/ethconfig/config.go @@ -154,7 +154,7 @@ type Config struct { // RPCEVMTimeout is the global timeout for eth-call. RPCEVMTimeout time.Duration - // RPCTxFeeCap is the global transaction fee(price * gaslimit) cap for + // RPCTxFeeCap is the global transaction fee (price * gas limit) cap for // send-transaction variants. The unit is ether. RPCTxFeeCap float64 diff --git a/eth/filters/filter.go b/eth/filters/filter.go index ada478ae1d..c4d787eb22 100644 --- a/eth/filters/filter.go +++ b/eth/filters/filter.go @@ -456,7 +456,6 @@ func (f *Filter) blockLogs(ctx context.Context, header *types.Header) ([]*types. // checkMatches checks if the receipts belonging to the given header contain any log events that // match the filter criteria. This function is called when the bloom filter signals a potential match. -// skipFilter signals all logs of the given block are requested. func (f *Filter) checkMatches(ctx context.Context, header *types.Header) ([]*types.Log, error) { hash := header.Hash() // Logs in cache are partially filled with context data diff --git a/eth/filters/filter_system.go b/eth/filters/filter_system.go index 82c91266c0..751cd417e8 100644 --- a/eth/filters/filter_system.go +++ b/eth/filters/filter_system.go @@ -207,7 +207,7 @@ type EventSystem struct { } // NewEventSystem creates a new manager that listens for event on the given mux, -// parses and filters them. It uses the all map to retrieve filter changes. The +// parses and filters them. It uses an internal map to retrieve filter changes. The // work loop holds its own index that is used to forward events to filters. // // The returned manager has a loop that needs to be stopped with the Stop function From 038ff766ff9f9d89c1593c75edeb101c0801a0a4 Mon Sep 17 00:00:00 2001 From: Ceyhun Onur Date: Fri, 1 Aug 2025 18:14:30 +0300 Subject: [PATCH 09/57] eth/filters: fix error when blockHash is used with fromBlock/toBlock (#31877) This introduces an error when the filter has both `blockHash` and `fromBlock`/`toBlock`, since these are mutually exclusive. Seems the tests were actually returning `not found` error, which went undetected since there was no check on the actual returned error in the test. --- eth/filters/api.go | 8 ++++ eth/filters/filter.go | 2 +- eth/filters/filter_system_test.go | 67 +++++++++++++++++++++++++------ 3 files changed, 63 insertions(+), 14 deletions(-) diff --git a/eth/filters/api.go b/eth/filters/api.go index 232af23957..c929810a12 100644 --- a/eth/filters/api.go +++ b/eth/filters/api.go @@ -38,6 +38,8 @@ var ( errInvalidTopic = errors.New("invalid topic(s)") errFilterNotFound = errors.New("filter not found") errInvalidBlockRange = errors.New("invalid block range params") + errUnknownBlock = errors.New("unknown block") + errBlockHashWithRange = errors.New("can't specify fromBlock/toBlock with blockHash") errPendingLogsUnsupported = errors.New("pending logs are not supported") errExceedMaxTopics = errors.New("exceed max topics") errExceedMaxAddresses = errors.New("exceed max addresses") @@ -348,8 +350,13 @@ func (api *FilterAPI) GetLogs(ctx context.Context, crit FilterCriteria) ([]*type if len(crit.Addresses) > maxAddresses { return nil, errExceedMaxAddresses } + var filter *Filter if crit.BlockHash != nil { + if crit.FromBlock != nil || crit.ToBlock != nil { + return nil, errBlockHashWithRange + } + // Block filter requested, construct a single-shot filter filter = api.sys.NewBlockFilter(*crit.BlockHash, crit.Addresses, crit.Topics) } else { @@ -372,6 +379,7 @@ func (api *FilterAPI) GetLogs(ctx context.Context, crit FilterCriteria) ([]*type // Construct the range filter filter = api.sys.NewRangeFilter(begin, end, crit.Addresses, crit.Topics) } + // Run the filter and return all the logs logs, err := filter.Logs(ctx) if err != nil { diff --git a/eth/filters/filter.go b/eth/filters/filter.go index c4d787eb22..1a9918d0ee 100644 --- a/eth/filters/filter.go +++ b/eth/filters/filter.go @@ -85,7 +85,7 @@ func (f *Filter) Logs(ctx context.Context) ([]*types.Log, error) { return nil, err } if header == nil { - return nil, errors.New("unknown block") + return nil, errUnknownBlock } if header.Number.Uint64() < f.sys.backend.HistoryPruningCutoff() { return nil, &history.PrunedHistoryError{} diff --git a/eth/filters/filter_system_test.go b/eth/filters/filter_system_test.go index 3e686ca2eb..013c1ae527 100644 --- a/eth/filters/filter_system_test.go +++ b/eth/filters/filter_system_test.go @@ -450,24 +450,65 @@ func TestInvalidGetLogsRequest(t *testing.T) { t.Parallel() var ( - db = rawdb.NewMemoryDatabase() - _, sys = newTestFilterSystem(db, Config{}) - api = NewFilterAPI(sys) - blockHash = common.HexToHash("0x1111111111111111111111111111111111111111111111111111111111111111") + genesis = &core.Genesis{ + Config: params.TestChainConfig, + BaseFee: big.NewInt(params.InitialBaseFee), + } + db, blocks, _ = core.GenerateChainWithGenesis(genesis, ethash.NewFaker(), 10, func(i int, gen *core.BlockGen) {}) + _, sys = newTestFilterSystem(db, Config{}) + api = NewFilterAPI(sys) + blockHash = blocks[0].Hash() + unknownBlockHash = common.HexToHash("0x1111111111111111111111111111111111111111111111111111111111111111") ) - // Reason: Cannot specify both BlockHash and FromBlock/ToBlock) - testCases := []FilterCriteria{ - 0: {BlockHash: &blockHash, FromBlock: big.NewInt(100)}, - 1: {BlockHash: &blockHash, ToBlock: big.NewInt(500)}, - 2: {BlockHash: &blockHash, FromBlock: big.NewInt(rpc.LatestBlockNumber.Int64())}, - 3: {BlockHash: &blockHash, Topics: [][]common.Hash{{}, {}, {}, {}, {}}}, - 4: {BlockHash: &blockHash, Addresses: make([]common.Address, maxAddresses+1)}, + // Insert the blocks into the chain so filter can look them up + 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(blocks); err != nil { + t.Fatalf("block %d: failed to insert into chain: %v", n, err) + } + + type testcase struct { + f FilterCriteria + err error + } + testCases := []testcase{ + { + f: FilterCriteria{BlockHash: &blockHash, FromBlock: big.NewInt(100)}, + err: errBlockHashWithRange, + }, + { + f: FilterCriteria{BlockHash: &blockHash, ToBlock: big.NewInt(500)}, + err: errBlockHashWithRange, + }, + { + f: FilterCriteria{BlockHash: &blockHash, FromBlock: big.NewInt(rpc.LatestBlockNumber.Int64())}, + err: errBlockHashWithRange, + }, + { + f: FilterCriteria{BlockHash: &unknownBlockHash}, + err: errUnknownBlock, + }, + { + f: FilterCriteria{BlockHash: &blockHash, Topics: [][]common.Hash{{}, {}, {}, {}, {}}}, + err: errExceedMaxTopics, + }, + { + f: FilterCriteria{BlockHash: &blockHash, Topics: [][]common.Hash{{}, {}, {}, {}, {}}}, + err: errExceedMaxTopics, + }, + { + f: FilterCriteria{BlockHash: &blockHash, Addresses: make([]common.Address, maxAddresses+1)}, + err: errExceedMaxAddresses, + }, } for i, test := range testCases { - if _, err := api.GetLogs(context.Background(), test); err == nil { - t.Errorf("Expected Logs for case #%d to fail", i) + _, err := api.GetLogs(context.Background(), test.f) + if !errors.Is(err, test.err) { + t.Errorf("case %d: wrong error: %q\nwant: %q", i, err, test.err) } } } From 5572f2ed229ff1f3aa0967e32af320a4b01be16d Mon Sep 17 00:00:00 2001 From: VolodymyrBg Date: Fri, 1 Aug 2025 19:30:48 +0300 Subject: [PATCH 10/57] rlp/rlpgen: implement package renaming support (#31148) This adds support for importing types from multiple identically-named packages. --------- Co-authored-by: Felix Lange --- rlp/rlpgen/gen.go | 101 ++++++++++++++++++++------- rlp/rlpgen/gen_test.go | 2 +- rlp/rlpgen/testdata/pkgclash.in.txt | 13 ++++ rlp/rlpgen/testdata/pkgclash.out.txt | 82 ++++++++++++++++++++++ 4 files changed, 173 insertions(+), 25 deletions(-) create mode 100644 rlp/rlpgen/testdata/pkgclash.in.txt create mode 100644 rlp/rlpgen/testdata/pkgclash.out.txt diff --git a/rlp/rlpgen/gen.go b/rlp/rlpgen/gen.go index ff39874737..64841b38a0 100644 --- a/rlp/rlpgen/gen.go +++ b/rlp/rlpgen/gen.go @@ -24,6 +24,7 @@ import ( "sort" "github.com/ethereum/go-ethereum/rlp/internal/rlpstruct" + "golang.org/x/tools/go/packages" ) // buildContext keeps the data needed for make*Op. @@ -96,14 +97,20 @@ func (bctx *buildContext) typeToStructType(typ types.Type) *rlpstruct.Type { // file and assigns unique names of temporary variables. type genContext struct { inPackage *types.Package - imports map[string]struct{} + imports map[string]genImportPackage tempCounter int } +type genImportPackage struct { + alias string + pkg *types.Package +} + func newGenContext(inPackage *types.Package) *genContext { return &genContext{ - inPackage: inPackage, - imports: make(map[string]struct{}), + inPackage: inPackage, + imports: make(map[string]genImportPackage), + tempCounter: 0, } } @@ -117,32 +124,78 @@ func (ctx *genContext) resetTemp() { ctx.tempCounter = 0 } -func (ctx *genContext) addImport(path string) { - if path == ctx.inPackage.Path() { - return // avoid importing the package that we're generating in. +func (ctx *genContext) addImportPath(path string) { + pkg, err := ctx.loadPackage(path) + if err != nil { + panic(fmt.Sprintf("can't load package %q: %v", path, err)) } - // TODO: renaming? - ctx.imports[path] = struct{}{} + ctx.addImport(pkg) } -// importsList returns all packages that need to be imported. -func (ctx *genContext) importsList() []string { - imp := make([]string, 0, len(ctx.imports)) - for k := range ctx.imports { - imp = append(imp, k) +func (ctx *genContext) addImport(pkg *types.Package) string { + if pkg.Path() == ctx.inPackage.Path() { + return "" // avoid importing the package that we're generating in } - sort.Strings(imp) - return imp + if p, exists := ctx.imports[pkg.Path()]; exists { + return p.alias + } + var ( + baseName = pkg.Name() + alias = baseName + counter = 1 + ) + // If the base name conflicts with an existing import, add a numeric suffix. + for ctx.hasAlias(alias) { + alias = fmt.Sprintf("%s%d", baseName, counter) + counter++ + } + ctx.imports[pkg.Path()] = genImportPackage{alias, pkg} + return alias } -// qualify is the types.Qualifier used for printing types. +// hasAlias checks if an alias is already in use +func (ctx *genContext) hasAlias(alias string) bool { + for _, p := range ctx.imports { + if p.alias == alias { + return true + } + } + return false +} + +// loadPackage attempts to load package information +func (ctx *genContext) loadPackage(path string) (*types.Package, error) { + cfg := &packages.Config{Mode: packages.NeedName} + pkgs, err := packages.Load(cfg, path) + if err != nil { + return nil, err + } + if len(pkgs) == 0 { + return nil, fmt.Errorf("no package found for path %s", path) + } + return types.NewPackage(path, pkgs[0].Name), nil +} + +// qualify is the types.Qualifier used for printing types func (ctx *genContext) qualify(pkg *types.Package) string { if pkg.Path() == ctx.inPackage.Path() { return "" } - ctx.addImport(pkg.Path()) - // TODO: renaming? - return pkg.Name() + return ctx.addImport(pkg) +} + +// importsList returns all packages that need to be imported +func (ctx *genContext) importsList() []string { + imp := make([]string, 0, len(ctx.imports)) + for path, p := range ctx.imports { + if p.alias == p.pkg.Name() { + imp = append(imp, fmt.Sprintf("%q", path)) + } else { + imp = append(imp, fmt.Sprintf("%s %q", p.alias, path)) + } + } + sort.Strings(imp) + return imp } type op interface { @@ -359,7 +412,7 @@ func (op uint256Op) genWrite(ctx *genContext, v string) string { } func (op uint256Op) genDecode(ctx *genContext) (string, string) { - ctx.addImport("github.com/holiman/uint256") + ctx.addImportPath("github.com/holiman/uint256") var b bytes.Buffer resultV := ctx.temp() @@ -732,7 +785,7 @@ func (bctx *buildContext) makeOp(name *types.Named, typ types.Type, tags rlpstru // generateDecoder generates the DecodeRLP method on 'typ'. func generateDecoder(ctx *genContext, typ string, op op) []byte { ctx.resetTemp() - ctx.addImport(pathOfPackageRLP) + ctx.addImportPath(pathOfPackageRLP) result, code := op.genDecode(ctx) var b bytes.Buffer @@ -747,8 +800,8 @@ func generateDecoder(ctx *genContext, typ string, op op) []byte { // generateEncoder generates the EncodeRLP method on 'typ'. func generateEncoder(ctx *genContext, typ string, op op) []byte { ctx.resetTemp() - ctx.addImport("io") - ctx.addImport(pathOfPackageRLP) + ctx.addImportPath("io") + ctx.addImportPath(pathOfPackageRLP) var b bytes.Buffer fmt.Fprintf(&b, "func (obj *%s) EncodeRLP(_w io.Writer) error {\n", typ) @@ -783,7 +836,7 @@ func (bctx *buildContext) generate(typ *types.Named, encoder, decoder bool) ([]b var b bytes.Buffer fmt.Fprintf(&b, "package %s\n\n", pkg.Name()) for _, imp := range ctx.importsList() { - fmt.Fprintf(&b, "import %q\n", imp) + fmt.Fprintf(&b, "import %s\n", imp) } if encoder { fmt.Fprintln(&b) diff --git a/rlp/rlpgen/gen_test.go b/rlp/rlpgen/gen_test.go index b4fabb3dc6..4bfb1b9d25 100644 --- a/rlp/rlpgen/gen_test.go +++ b/rlp/rlpgen/gen_test.go @@ -47,7 +47,7 @@ func init() { } } -var tests = []string{"uints", "nil", "rawvalue", "optional", "bigint", "uint256"} +var tests = []string{"uints", "nil", "rawvalue", "optional", "bigint", "uint256", "pkgclash"} func TestOutput(t *testing.T) { for _, test := range tests { diff --git a/rlp/rlpgen/testdata/pkgclash.in.txt b/rlp/rlpgen/testdata/pkgclash.in.txt new file mode 100644 index 0000000000..1d407881ce --- /dev/null +++ b/rlp/rlpgen/testdata/pkgclash.in.txt @@ -0,0 +1,13 @@ +// -*- mode: go -*- + +package test + +import ( + eth1 "github.com/ethereum/go-ethereum/eth" + eth2 "github.com/ethereum/go-ethereum/eth/protocols/eth" +) + +type Test struct { + A eth1.MinerAPI + B eth2.GetReceiptsPacket +} diff --git a/rlp/rlpgen/testdata/pkgclash.out.txt b/rlp/rlpgen/testdata/pkgclash.out.txt new file mode 100644 index 0000000000..d119639b99 --- /dev/null +++ b/rlp/rlpgen/testdata/pkgclash.out.txt @@ -0,0 +1,82 @@ +package test + +import "github.com/ethereum/go-ethereum/common" +import "github.com/ethereum/go-ethereum/eth" +import "github.com/ethereum/go-ethereum/rlp" +import "io" +import eth1 "github.com/ethereum/go-ethereum/eth/protocols/eth" + +func (obj *Test) EncodeRLP(_w io.Writer) error { + w := rlp.NewEncoderBuffer(_w) + _tmp0 := w.List() + _tmp1 := w.List() + w.ListEnd(_tmp1) + _tmp2 := w.List() + w.WriteUint64(obj.B.RequestId) + _tmp3 := w.List() + for _, _tmp4 := range obj.B.GetReceiptsRequest { + w.WriteBytes(_tmp4[:]) + } + w.ListEnd(_tmp3) + w.ListEnd(_tmp2) + w.ListEnd(_tmp0) + return w.Flush() +} + +func (obj *Test) DecodeRLP(dec *rlp.Stream) error { + var _tmp0 Test + { + if _, err := dec.List(); err != nil { + return err + } + // A: + var _tmp1 eth.MinerAPI + { + if _, err := dec.List(); err != nil { + return err + } + if err := dec.ListEnd(); err != nil { + return err + } + } + _tmp0.A = _tmp1 + // B: + var _tmp2 eth1.GetReceiptsPacket + { + if _, err := dec.List(); err != nil { + return err + } + // RequestId: + _tmp3, err := dec.Uint64() + if err != nil { + return err + } + _tmp2.RequestId = _tmp3 + // GetReceiptsRequest: + var _tmp4 []common.Hash + if _, err := dec.List(); err != nil { + return err + } + for dec.MoreDataInList() { + var _tmp5 common.Hash + if err := dec.ReadBytes(_tmp5[:]); err != nil { + return err + } + _tmp4 = append(_tmp4, _tmp5) + } + if err := dec.ListEnd(); err != nil { + return err + } + _tmp2.GetReceiptsRequest = _tmp4 + if err := dec.ListEnd(); err != nil { + return err + } + } + _tmp0.B = _tmp2 + if err := dec.ListEnd(); err != nil { + return err + } + } + *obj = _tmp0 + return nil +} From 5ebd8032b91c305f16c44ab312bde0c373ad5e05 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felf=C3=B6ldi=20Zsolt?= Date: Mon, 4 Aug 2025 03:19:33 +0200 Subject: [PATCH 11/57] beacon/params, core/filtermaps: update checkpoints (#32336) This PR updates checkpoints for blsync and filtermaps. --- beacon/params/checkpoint_holesky.hex | 2 +- beacon/params/checkpoint_hoodi.hex | 1 + beacon/params/checkpoint_mainnet.hex | 2 +- beacon/params/checkpoint_sepolia.hex | 2 +- beacon/params/networks.go | 5 +++- core/filtermaps/checkpoints_holesky.json | 8 ++++++- core/filtermaps/checkpoints_mainnet.json | 23 ++++++++++++++++++- core/filtermaps/checkpoints_sepolia.json | 29 +++++++++++++++++++++++- 8 files changed, 65 insertions(+), 7 deletions(-) create mode 100644 beacon/params/checkpoint_hoodi.hex diff --git a/beacon/params/checkpoint_holesky.hex b/beacon/params/checkpoint_holesky.hex index 740d7aba21..f4667305b4 100644 --- a/beacon/params/checkpoint_holesky.hex +++ b/beacon/params/checkpoint_holesky.hex @@ -1 +1 @@ -0xd60e5310c5d52ced44cfb13be4e9f22a1e6a6dc56964c3cccd429182d26d72d0 \ No newline at end of file +0x4bae4b97deda095724560012cab1f80a5221ce0a37a4b5236d8ab63f595f29d9 \ No newline at end of file diff --git a/beacon/params/checkpoint_hoodi.hex b/beacon/params/checkpoint_hoodi.hex new file mode 100644 index 0000000000..2885d7c996 --- /dev/null +++ b/beacon/params/checkpoint_hoodi.hex @@ -0,0 +1 @@ +0x1bbf958008172591b6cbdb3d8d52e26998258e83d4bdb9eec10969d84519a6bd \ No newline at end of file diff --git a/beacon/params/checkpoint_mainnet.hex b/beacon/params/checkpoint_mainnet.hex index 45f065ca15..417e69a24b 100644 --- a/beacon/params/checkpoint_mainnet.hex +++ b/beacon/params/checkpoint_mainnet.hex @@ -1 +1 @@ -0x02f0bb348b0d45f95a9b7e2bb5705768ad06548876cee03d880a2c9dabb1ff88 \ No newline at end of file +0x2fe39a39b6f7cbd549e0f74d259de6db486005a65bd3bd92840dd6ce21d6f4c8 \ No newline at end of file diff --git a/beacon/params/checkpoint_sepolia.hex b/beacon/params/checkpoint_sepolia.hex index 3d1b2885b3..02faf72187 100644 --- a/beacon/params/checkpoint_sepolia.hex +++ b/beacon/params/checkpoint_sepolia.hex @@ -1 +1 @@ -0xa0dad451a230c01be6f2492980ec5bb412d8cf33351a75e8b172b5b84a5fd03a \ No newline at end of file +0x86686b2b366e24134e0e3969a9c5f3759f92e5d2b04785b42e22cc7d468c2107 \ No newline at end of file diff --git a/beacon/params/networks.go b/beacon/params/networks.go index 51f67e0c97..b35db34fd6 100644 --- a/beacon/params/networks.go +++ b/beacon/params/networks.go @@ -31,6 +31,9 @@ var checkpointSepolia string //go:embed checkpoint_holesky.hex var checkpointHolesky string +//go:embed checkpoint_hoodi.hex +var checkpointHoodi string + var ( MainnetLightConfig = (&ChainConfig{ GenesisValidatorsRoot: common.HexToHash("0x4b363db94e286120d76eb905340fdd4e54bfe9f06bf33ff6cf5ad27f511bfe95"), @@ -71,7 +74,7 @@ var ( HoodiLightConfig = (&ChainConfig{ GenesisValidatorsRoot: common.HexToHash("0x212f13fc4df078b6cb7db228f1c8307566dcecf900867401a92023d7ba99cb5f"), GenesisTime: 1742212800, - Checkpoint: common.HexToHash(""), + Checkpoint: common.HexToHash(checkpointHoodi), }). AddFork("GENESIS", 0, common.FromHex("0x10000910")). AddFork("ALTAIR", 0, common.FromHex("0x20000910")). diff --git a/core/filtermaps/checkpoints_holesky.json b/core/filtermaps/checkpoints_holesky.json index a56611cc8e..481c71a114 100644 --- a/core/filtermaps/checkpoints_holesky.json +++ b/core/filtermaps/checkpoints_holesky.json @@ -18,5 +18,11 @@ {"blockNumber": 3221725, "blockId": "0xe771f897dece48b1583cc1d1d10de8015da57407eb1fdf239fdbe46eaab85143", "firstIndex": 1140850137}, {"blockNumber": 3357164, "blockId": "0x6252d0aa54c79623b0680069c88d7b5c47983f0d5c4845b6c811b8d9b5e8ff3c", "firstIndex": 1207959453}, {"blockNumber": 3447019, "blockId": "0xeb7d585e1e063f3cc05ed399fbf6c2df63c271f62f030acb804e9fb1e74b6dc1", "firstIndex": 1275067542}, -{"blockNumber": 3546397, "blockId": "0xdabdef7defa4281180a57c5af121877b82274f15ccf074ea0096146f4c246df2", "firstIndex": 1342176778} +{"blockNumber": 3546397, "blockId": "0xdabdef7defa4281180a57c5af121877b82274f15ccf074ea0096146f4c246df2", "firstIndex": 1342176778}, +{"blockNumber": 3867885, "blockId": "0x8be069dd7a3e2ffb869ee164d11b28555233d2510b134ab9d5484fdae55d2225", "firstIndex": 1409285539}, +{"blockNumber": 3935446, "blockId": "0xc91a61bc215bbcccc3020c62e5c8153162df0d8bcc59813d74671b2d24903ed7", "firstIndex": 1476394742}, +{"blockNumber": 3989508, "blockId": "0xc85dec36a767e44237842ef51915944c2a49780c8c394a3aa6cfb013c99cf58b", "firstIndex": 1543503452}, +{"blockNumber": 4057078, "blockId": "0xccdb79f6705629cb6ab1667a1244938f60911236549143fcff23a3989213e67e", "firstIndex": 1610612030}, +{"blockNumber": 4126499, "blockId": "0x92f2ef21fc911e87e81e38373d5f2915587b9648a0ab3cf4fcfe3e5aaffe7b85", "firstIndex": 1677720416}, +{"blockNumber": 4239335, "blockId": "0x64fbd22965eb583a584552b7edb9b7ce26fb6aad247c1063d0d5a4d11cbcc58c", "firstIndex": 1744830176} ] diff --git a/core/filtermaps/checkpoints_mainnet.json b/core/filtermaps/checkpoints_mainnet.json index 70a08b1aaf..2ea065ddb7 100644 --- a/core/filtermaps/checkpoints_mainnet.json +++ b/core/filtermaps/checkpoints_mainnet.json @@ -267,5 +267,26 @@ {"blockNumber": 22168652, "blockId": "0x6ae43618c915e636794e2cc2d75dde9992766881c7405fe6479c045ed4bee57e", "firstIndex": 17850956277}, {"blockNumber": 22190975, "blockId": "0x9437121647899a4b7b84d67fbea7cc6ff967481c2eab4328ccd86e2cefe19420", "firstIndex": 17918066140}, {"blockNumber": 22234357, "blockId": "0x036030830134f9224160d5a0b62da35ec7813dc8855d554bd22e9d38545243ed", "firstIndex": 17985175075}, -{"blockNumber": 22276736, "blockId": "0x5ceb96d98aa1b4c1c2f2fa253ae9cdb1b04e0420c11bf795400e8762c0a1635c", "firstIndex": 18052284344} +{"blockNumber": 22276736, "blockId": "0x5ceb96d98aa1b4c1c2f2fa253ae9cdb1b04e0420c11bf795400e8762c0a1635c", "firstIndex": 18052284344}, +{"blockNumber": 22321282, "blockId": "0x8a601ebf6a757020c6d43a978f0bd2c150c4acc1ffdd50c7ee88afc78b0c11f8", "firstIndex": 18119392242}, +{"blockNumber": 22349231, "blockId": "0xb751c026a92ba5be95ad7ea4e2729a175b0d0e11a4c108f47cab232b4715d1a2", "firstIndex": 18186501218}, +{"blockNumber": 22377469, "blockId": "0xa47916860a22f7e26761ec2d7f717410791bd3ed0237b2f6266750214c7bbf08", "firstIndex": 18253610249}, +{"blockNumber": 22422685, "blockId": "0x8beaee39603af55fad222730f556c840c41cd76a5eef0bad367ac94d3b86c7aa", "firstIndex": 18320716377}, +{"blockNumber": 22462378, "blockId": "0x6dba9c5d2949f5a6a072267b590e8b15e6fb157a0fc22719387f1fd6bfcd8d5d", "firstIndex": 18387828426}, +{"blockNumber": 22500185, "blockId": "0x2484c380df0a8f7edfdf8d917570d23fab8499aea80c35b6cf4e5fe1e34106e9", "firstIndex": 18454936227}, +{"blockNumber": 22539624, "blockId": "0xd418071906803d25afc3842a6a6468ad3b5fea27107b314ce4e2ccf08b478acf", "firstIndex": 18522044531}, +{"blockNumber": 22577021, "blockId": "0xff222982693f3ff60d2097822171f80a6ddd979080aeb7e995bfb1b973497c84", "firstIndex": 18589154438}, +{"blockNumber": 22614525, "blockId": "0x9868da1fea2ffca3f67e35570f02eb5707b27f6967ea4a109eb4ddbf24566efd", "firstIndex": 18656264174}, +{"blockNumber": 22652848, "blockId": "0x060a911da11ab0f1dda307f5196e622d23901d198925749e70ab58a439477c5a", "firstIndex": 18723372617}, +{"blockNumber": 22692432, "blockId": "0x6a937f2c283aba8c778c1f5ef340b225fd820f8a7dfa6f24f5fe541994f32f2d", "firstIndex": 18790480232}, +{"blockNumber": 22731200, "blockId": "0x00d57a9e7a2dad252436fe9f0382c6a8860d301a9f9ffe6d7ac64c82b95300f8", "firstIndex": 18857590076}, +{"blockNumber": 22769000, "blockId": "0xa48db20307c19c373ef2d31d85088ea14b8df0450491c31982504c87b04edbc0", "firstIndex": 18924699130}, +{"blockNumber": 22808126, "blockId": "0x1419c64ff003edca0586f1c8ec3063da5c54c57ff826cfb34bc866cc18949653", "firstIndex": 18991807807}, +{"blockNumber": 22845231, "blockId": "0x691f87217e61c5d7ae9ad53a44d30e1ab6b1cc3f2b689b9fbf7c38fbacacfe3e", "firstIndex": 19058917062}, +{"blockNumber": 22884189, "blockId": "0x7f102d44c0ea7803f5b0e1a98a6abf0e8383eb99fb114d6f7b4591753ce8bba3", "firstIndex": 19126024122}, +{"blockNumber": 22920923, "blockId": "0x04fe6179495016fc3fe56d8ef5311c360a5761a898262173849c3494fdd73d92", "firstIndex": 19193134595}, +{"blockNumber": 22958100, "blockId": "0xe38e0ff7b0c4065ca42ea577bc32f2566ca46f2ddeedcc4bc1f8fb00e7f26329", "firstIndex": 19260242424}, +{"blockNumber": 22988600, "blockId": "0x04ca74758b22e0ea54b8c992022ff21c16a2af9c45144c3b0f80de921a7eee82", "firstIndex": 19327351273}, +{"blockNumber": 23018392, "blockId": "0x61cc979b00bc97b48356f986a5b9ec997d674bc904c2a2e4b0f17de08e50b3bb", "firstIndex": 19394459627}, +{"blockNumber": 23048524, "blockId": "0x489de15d95739ede4ab15e8b5151d80d4dc85ae10e7be800b1a4723094a678df", "firstIndex": 19461570073} ] diff --git a/core/filtermaps/checkpoints_sepolia.json b/core/filtermaps/checkpoints_sepolia.json index 8d799daefd..234af955e8 100644 --- a/core/filtermaps/checkpoints_sepolia.json +++ b/core/filtermaps/checkpoints_sepolia.json @@ -68,5 +68,32 @@ {"blockNumber": 7911722, "blockId": "0x9a85e48e3135c97c51fc1786f2af0596c802e021b6c53cfca65a129cafcd23ed", "firstIndex": 4496287265}, {"blockNumber": 7960147, "blockId": "0xc9359cc76d7090e1c8a031108f0ab7a8935d971efd4325fe53612a1d99562f6f", "firstIndex": 4563402388}, {"blockNumber": 8030418, "blockId": "0x21867e68cd8327aed2da2601399d60f7f9e41dca4a4f2f9be982e5a2b9304a88", "firstIndex": 4630511616}, -{"blockNumber": 8087701, "blockId": "0x0fa8c8d7549cc9a8d308262706fe248efe759f8b63511efb1e7f3926e9af2dcb", "firstIndex": 4697614758} +{"blockNumber": 8087701, "blockId": "0x0fa8c8d7549cc9a8d308262706fe248efe759f8b63511efb1e7f3926e9af2dcb", "firstIndex": 4697614758}, +{"blockNumber": 8149130, "blockId": "0x655ea638fd9e35cc25f4332f260d7bf98f4f6fa9a72e1bff861209f18659e94c", "firstIndex": 4764727744}, +{"blockNumber": 8208672, "blockId": "0xb5847a670dc3b6181f9e2e40e4218548048366d237a0d12e938b9879bc8cf800", "firstIndex": 4831837882}, +{"blockNumber": 8271345, "blockId": "0x96797214946f29093883b877ccb0f2a9f771a9a3db3794a642b5dcb781c4d194", "firstIndex": 4898942160}, +{"blockNumber": 8302858, "blockId": "0x6a5977b3382ca69a9e0412333f97b911c1f69f857d8f31dd0fc930980e24f2fc", "firstIndex": 4966054626}, +{"blockNumber": 8333618, "blockId": "0x2547294aa23b67c42adbdddfcf424b17a95c4ff0f352a6a2442c529cfb0c892a", "firstIndex": 5033163605}, +{"blockNumber": 8360582, "blockId": "0xf34f5dceb0ef22e0f782b56c12790472acc675997b9c45075bd4e18a9dacd03c", "firstIndex": 5100273631}, +{"blockNumber": 8387230, "blockId": "0x0fbea42e87620b5beeb76b67febc173847c54333d7dce9fa2f8f2a3fa9c8c22a", "firstIndex": 5167381673}, +{"blockNumber": 8414795, "blockId": "0x6c9c000cf5e35da3a7e9e1cd56147c8ce9b43a76d6de945675efd9dc03b628c9", "firstIndex": 5234477010}, +{"blockNumber": 8444749, "blockId": "0xba85f8c9abaddc34e2113eb49385667ba4b008168ae701f46aa7a7ce78c633a1", "firstIndex": 5301598562}, +{"blockNumber": 8474551, "blockId": "0x720866a40242f087dd25b6f0dd79224884f435b114a39e60c5669f5c942c78c1", "firstIndex": 5368707262}, +{"blockNumber": 8501310, "blockId": "0x2b6da233532c701202fb5ac67e005f7d3eb71f88a9fac10c25d24dd11ada05e5", "firstIndex": 5435803858}, +{"blockNumber": 8526970, "blockId": "0x005f9bbad0a10234129d09894d7fcf04bf1398d326510eedb4195808c282802d", "firstIndex": 5502926509}, +{"blockNumber": 8550412, "blockId": "0x37c9f3efc9f33cf62f590087c8c9ac70011883f75e648647a6fd0fec00ca627c", "firstIndex": 5570034950}, +{"blockNumber": 8573540, "blockId": "0x81cfb46a07be7c70bb8a0f76b03a4cd502f92032bea68ad7ba10e26351673000", "firstIndex": 5637137662}, +{"blockNumber": 8590416, "blockId": "0x5c223d58ef22d7b0dd8c498e8498da4787b5dc706681c2bc83849441f5d0922d", "firstIndex": 5704252906}, +{"blockNumber": 8616793, "blockId": "0x9043ce02742fb5ec43a696602867b7ce6003a95b36cd28a37eeb9785a46ad49f", "firstIndex": 5771357264}, +{"blockNumber": 8647290, "blockId": "0xd90115193764b0a33f3f2a719381b3ddbce2532607c72fb287a864eb391eeada", "firstIndex": 5838466144}, +{"blockNumber": 8673192, "blockId": "0x9bc92d340cccaf4c8c03372efc24eb92c5159106729de8d2e9e064f5568d082b", "firstIndex": 5905577457}, +{"blockNumber": 8700694, "blockId": "0xb3d656a173b962bc6825198e94a4974289db06a8998060bd0f5ee2044a7a7deb", "firstIndex": 5972679345}, +{"blockNumber": 8724533, "blockId": "0x253ffc6d77b88fe18736e4c313e9930341c444bc87b2ee22b26cfe8d9d0b178d", "firstIndex": 6039795829}, +{"blockNumber": 8743948, "blockId": "0x04eb66d0261705d31e629193148d0685058d7759ba5f95d2d38e412dbadb8256", "firstIndex": 6106901747}, +{"blockNumber": 8758378, "blockId": "0x64adf54e662d11db716610157da672c3d8b45f001dbce40a269871b86a84d026", "firstIndex": 6174011544}, +{"blockNumber": 8777722, "blockId": "0x0a7f9a956024b404c915e70b42221aa027b2dd715b0697f099dccefae0b9af97", "firstIndex": 6241124215}, +{"blockNumber": 8800154, "blockId": "0x411f90dc18f2bca31fa63615c2866c907bbac1fae8c06782cabfaf788efba665", "firstIndex": 6308233216}, +{"blockNumber": 8829725, "blockId": "0x5686f3a5eec1b070d0113c588f8f4a560d57ad96b8045cedb5c08bbadaa0273e", "firstIndex": 6375340033}, +{"blockNumber": 8858036, "blockId": "0x4f9b5d9fac9c6f6e2224f613cda12e8ab95d636774ce87489dce8a9f805ee2e5", "firstIndex": 6442450330}, +{"blockNumber": 8884811, "blockId": "0x9cf74f978872683802c065e72b5a5326fdad95f19733c34d927b575cd85fd0bd", "firstIndex": 6509559380} ] From dd1ebac11757484575ee779381af32f29ce3fbe4 Mon Sep 17 00:00:00 2001 From: rjl493456442 Date: Mon, 4 Aug 2025 21:59:08 +0800 Subject: [PATCH 12/57] version: release v1.16.2 (#32343) --- version/version.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/version/version.go b/version/version.go index ab1559d8aa..37f1d52bbe 100644 --- a/version/version.go +++ b/version/version.go @@ -17,8 +17,8 @@ package version const ( - Major = 1 // Major version component of the current release - Minor = 16 // Minor version component of the current release - Patch = 2 // Patch version component of the current release - Meta = "unstable" // Version metadata to append to the version string + Major = 1 // Major version component of the current release + Minor = 16 // Minor version component of the current release + Patch = 2 // Patch version component of the current release + Meta = "stable" // Version metadata to append to the version string ) From 073e7ec4b0e99aba1b1f16e3556e1f261a0136f4 Mon Sep 17 00:00:00 2001 From: rjl493456442 Date: Mon, 4 Aug 2025 22:24:38 +0800 Subject: [PATCH 13/57] version: begin v1.16.3 release cycle (#32345) --- version/version.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/version/version.go b/version/version.go index 37f1d52bbe..30c81b804b 100644 --- a/version/version.go +++ b/version/version.go @@ -17,8 +17,8 @@ package version const ( - Major = 1 // Major version component of the current release - Minor = 16 // Minor version component of the current release - Patch = 2 // Patch version component of the current release - Meta = "stable" // Version metadata to append to the version string + Major = 1 // Major version component of the current release + Minor = 16 // Minor version component of the current release + Patch = 3 // Patch version component of the current release + Meta = "unstable" // Version metadata to append to the version string ) From cf500264664c42c259be955961d54b385ffd5c02 Mon Sep 17 00:00:00 2001 From: Guillaume Ballet <3272758+gballet@users.noreply.github.com> Date: Tue, 5 Aug 2025 03:34:12 +0200 Subject: [PATCH 14/57] core/state: introduce the TransitionState object (verkle transition part 1) (#31634) This is the first part of #31532 It maintains a series of conversion maker which are to be updated by the conversion code (in a follow-up PR, this is a breakdown of a larger PR to make things easier to review). They can be used in this way: - During the conversion, by storing the conversion markers when the block has been processed. This is meant to be written in a function that isn't currently present, hence [this TODO](https://github.com/ethereum/go-ethereum/pull/31634/files#diff-89272f61e115723833d498a0acbe59fa2286e3dc7276a676a7f7816f21e248b7R384). Part of https://github.com/ethereum/go-ethereum/issues/31583 --------- Signed-off-by: Guillaume Ballet <3272758+gballet@users.noreply.github.com> Co-authored-by: Gary Rong --- core/chain_makers.go | 4 +- core/overlay/state_transition.go | 105 +++++++++++++++++++++++++++++++ core/rawdb/accessors_overlay.go | 30 +++++++++ core/rawdb/database.go | 2 +- core/rawdb/schema.go | 8 +++ core/state/database.go | 28 ++++++--- core/state/reader.go | 1 + core/verkle_witness_test.go | 6 +- 8 files changed, 171 insertions(+), 13 deletions(-) create mode 100644 core/overlay/state_transition.go create mode 100644 core/rawdb/accessors_overlay.go diff --git a/core/chain_makers.go b/core/chain_makers.go index b2559495a1..af55716cca 100644 --- a/core/chain_makers.go +++ b/core/chain_makers.go @@ -540,8 +540,10 @@ func GenerateVerkleChain(config *params.ChainConfig, parent *types.Block, engine return block, b.receipts } + sdb := state.NewDatabase(trdb, nil) + for i := 0; i < n; i++ { - statedb, err := state.New(parent.Root(), state.NewDatabase(trdb, nil)) + statedb, err := state.New(parent.Root(), sdb) if err != nil { panic(err) } diff --git a/core/overlay/state_transition.go b/core/overlay/state_transition.go new file mode 100644 index 0000000000..90b5c9431a --- /dev/null +++ b/core/overlay/state_transition.go @@ -0,0 +1,105 @@ +// 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 overlay + +import ( + "bytes" + "encoding/gob" + + "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" +) + +// TransitionState is a structure that holds the progress markers of the +// translation process. +type TransitionState struct { + CurrentAccountAddress *common.Address // addresss of the last translated account + CurrentSlotHash common.Hash // hash of the last translated storage slot + CurrentPreimageOffset int64 // next byte to read from the preimage file + Started, Ended bool + + // Mark whether the storage for an account has been processed. This is useful if the + // maximum number of leaves of the conversion is reached before the whole storage is + // processed. + StorageProcessed bool + + BaseRoot common.Hash // hash of the last read-only MPT base tree +} + +// InTransition returns true if the translation process is in progress. +func (ts *TransitionState) InTransition() bool { + return ts != nil && ts.Started && !ts.Ended +} + +// Transitioned returns true if the translation process has been completed. +func (ts *TransitionState) Transitioned() bool { + return ts != nil && ts.Ended +} + +// Copy returns a deep copy of the TransitionState object. +func (ts *TransitionState) Copy() *TransitionState { + ret := &TransitionState{ + Started: ts.Started, + Ended: ts.Ended, + CurrentSlotHash: ts.CurrentSlotHash, + CurrentPreimageOffset: ts.CurrentPreimageOffset, + StorageProcessed: ts.StorageProcessed, + } + if ts.CurrentAccountAddress != nil { + addr := *ts.CurrentAccountAddress + ret.CurrentAccountAddress = &addr + } + return ret +} + +// LoadTransitionState retrieves the Verkle transition state associated with +// the given state root hash from the database. +func LoadTransitionState(db ethdb.KeyValueReader, root common.Hash, isVerkle bool) *TransitionState { + var ts *TransitionState + + data, _ := rawdb.ReadVerkleTransitionState(db, root) + + // if a state could be read from the db, attempt to decode it + if len(data) > 0 { + var ( + newts TransitionState + buf = bytes.NewBuffer(data[:]) + dec = gob.NewDecoder(buf) + ) + // Decode transition state + err := dec.Decode(&newts) + if err != nil { + log.Error("failed to decode transition state", "err", err) + return nil + } + ts = &newts + } + + // Fallback that should only happen before the transition + if ts == nil { + // Initialize the first transition state, with the "ended" + // field set to true if the database was created + // as a verkle database. + log.Debug("no transition state found, starting fresh", "is verkle", db) + + // Start with a fresh state + ts = &TransitionState{Ended: isVerkle} + } + return ts +} diff --git a/core/rawdb/accessors_overlay.go b/core/rawdb/accessors_overlay.go new file mode 100644 index 0000000000..364cc889d1 --- /dev/null +++ b/core/rawdb/accessors_overlay.go @@ -0,0 +1,30 @@ +// 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 rawdb + +import ( + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/ethdb" +) + +func ReadVerkleTransitionState(db ethdb.KeyValueReader, hash common.Hash) ([]byte, error) { + return db.Get(transitionStateKey(hash)) +} + +func WriteVerkleTransitionState(db ethdb.KeyValueWriter, hash common.Hash, state []byte) error { + return db.Put(transitionStateKey(hash), state) +} diff --git a/core/rawdb/database.go b/core/rawdb/database.go index 2ebdf360b5..25cd20d164 100644 --- a/core/rawdb/database.go +++ b/core/rawdb/database.go @@ -604,7 +604,7 @@ var knownMetadataKeys = [][]byte{ snapshotGeneratorKey, snapshotRecoveryKey, txIndexTailKey, fastTxLookupLimitKey, uncleanShutdownKey, badBlockKey, transitionStatusKey, skeletonSyncStatusKey, persistentStateIDKey, trieJournalKey, snapshotSyncStatusKey, snapSyncStatusFlagKey, - filterMapsRangeKey, headStateHistoryIndexKey, + filterMapsRangeKey, headStateHistoryIndexKey, VerkleTransitionStatePrefix, } // printChainMetadata prints out chain metadata to stderr. diff --git a/core/rawdb/schema.go b/core/rawdb/schema.go index 388a08f243..72f9bd34ec 100644 --- a/core/rawdb/schema.go +++ b/core/rawdb/schema.go @@ -158,6 +158,9 @@ var ( preimageCounter = metrics.NewRegisteredCounter("db/preimage/total", nil) preimageHitsCounter = metrics.NewRegisteredCounter("db/preimage/hits", nil) preimageMissCounter = metrics.NewRegisteredCounter("db/preimage/miss", nil) + + // Verkle transition information + VerkleTransitionStatePrefix = []byte("verkle-transition-state-") ) // LegacyTxLookupEntry is the legacy TxLookupEntry definition with some unnecessary @@ -397,3 +400,8 @@ func storageHistoryIndexBlockKey(addressHash common.Hash, storageHash common.Has binary.BigEndian.PutUint32(buf[:], blockID) return append(append(append(StateHistoryStorageBlockPrefix, addressHash.Bytes()...), storageHash.Bytes()...), buf[:]...) } + +// transitionStateKey = transitionStatusKey + hash +func transitionStateKey(hash common.Hash) []byte { + return append(VerkleTransitionStatePrefix, hash.Bytes()...) +} diff --git a/core/state/database.go b/core/state/database.go index 5fb198a629..b46e5d500d 100644 --- a/core/state/database.go +++ b/core/state/database.go @@ -21,6 +21,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/lru" + "github.com/ethereum/go-ethereum/core/overlay" "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/state/snapshot" "github.com/ethereum/go-ethereum/core/types" @@ -151,17 +152,21 @@ type CachingDB struct { codeCache *lru.SizeConstrainedCache[common.Hash, []byte] codeSizeCache *lru.Cache[common.Hash, int] pointCache *utils.PointCache + + // Transition-specific fields + TransitionStatePerRoot *lru.Cache[common.Hash, *overlay.TransitionState] } // NewDatabase creates a state database with the provided data sources. func NewDatabase(triedb *triedb.Database, snap *snapshot.Tree) *CachingDB { return &CachingDB{ - disk: triedb.Disk(), - triedb: triedb, - snap: snap, - codeCache: lru.NewSizeConstrainedCache[common.Hash, []byte](codeCacheSize), - codeSizeCache: lru.NewCache[common.Hash, int](codeSizeCacheSize), - pointCache: utils.NewPointCache(pointCacheSize), + disk: triedb.Disk(), + triedb: triedb, + snap: snap, + codeCache: lru.NewSizeConstrainedCache[common.Hash, []byte](codeCacheSize), + codeSizeCache: lru.NewCache[common.Hash, int](codeSizeCacheSize), + pointCache: utils.NewPointCache(pointCacheSize), + TransitionStatePerRoot: lru.NewCache[common.Hash, *overlay.TransitionState](1000), } } @@ -224,7 +229,13 @@ func (db *CachingDB) ReadersWithCacheStats(stateRoot common.Hash) (ReaderWithSta // OpenTrie opens the main account trie at a specific root hash. func (db *CachingDB) OpenTrie(root common.Hash) (Trie, error) { if db.triedb.IsVerkle() { - return trie.NewVerkleTrie(root, db.triedb, db.pointCache) + ts := overlay.LoadTransitionState(db.TrieDB().Disk(), root, db.triedb.IsVerkle()) + if ts.InTransition() { + panic("transition isn't supported yet") + } + if ts.Transitioned() { + return trie.NewVerkleTrie(root, db.triedb, db.pointCache) + } } tr, err := trie.NewStateTrie(trie.StateTrieID(root), db.triedb) if err != nil { @@ -235,9 +246,6 @@ func (db *CachingDB) OpenTrie(root common.Hash) (Trie, error) { // OpenStorageTrie opens the storage trie of an account. func (db *CachingDB) OpenStorageTrie(stateRoot common.Hash, address common.Address, root common.Hash, self Trie) (Trie, error) { - // In the verkle case, there is only one tree. But the two-tree structure - // is hardcoded in the codebase. So we need to return the same trie in this - // case. if db.triedb.IsVerkle() { return self, nil } diff --git a/core/state/reader.go b/core/state/reader.go index 4628f4d5db..f56a1bfae1 100644 --- a/core/state/reader.go +++ b/core/state/reader.go @@ -241,6 +241,7 @@ func newTrieReader(root common.Hash, db *triedb.Database, cache *utils.PointCach if !db.IsVerkle() { tr, err = trie.NewStateTrie(trie.StateTrieID(root), db) } else { + // TODO @gballet determine the trie type (verkle or overlay) by transition state tr, err = trie.NewVerkleTrie(root, db, cache) } if err != nil { diff --git a/core/verkle_witness_test.go b/core/verkle_witness_test.go index a89672e6e5..e200bf7f50 100644 --- a/core/verkle_witness_test.go +++ b/core/verkle_witness_test.go @@ -20,6 +20,7 @@ import ( "bytes" "encoding/binary" "encoding/hex" + "fmt" "math/big" "slices" "testing" @@ -202,12 +203,15 @@ func TestProcessVerkle(t *testing.T) { t.Log("verified verkle proof, inserting blocks into the chain") + for i, b := range chain { + fmt.Printf("%d %x\n", i, b.Root()) + } endnum, err := blockchain.InsertChain(chain) if err != nil { t.Fatalf("block %d imported with error: %v", endnum, err) } - for i := 0; i < 2; i++ { + for i := range 2 { b := blockchain.GetBlockByNumber(uint64(i) + 1) if b == nil { t.Fatalf("expected block %d to be present in chain", i+1) From e9dca3b1810054052a7186a4d3e9a3f52d25c3fe Mon Sep 17 00:00:00 2001 From: maskpp Date: Tue, 5 Aug 2025 13:07:45 +0800 Subject: [PATCH 15/57] eth/catalyst: avoid load the same blob tx multi times (#32190) - If all the `vhashes` are in the same `sidecar`, then it will load the same blob tx many times. This PR aims to upgrade this. --------- Co-authored-by: Gary Rong --- core/txpool/blobpool/blobpool.go | 103 ++++++++--- core/txpool/blobpool/blobpool_test.go | 242 ++++++++++++++++++++++---- eth/catalyst/api.go | 85 +++------ 3 files changed, 306 insertions(+), 124 deletions(-) diff --git a/core/txpool/blobpool/blobpool.go b/core/txpool/blobpool/blobpool.go index 078af34864..948ecd14c3 100644 --- a/core/txpool/blobpool/blobpool.go +++ b/core/txpool/blobpool/blobpool.go @@ -36,6 +36,7 @@ import ( "github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/txpool" "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/crypto/kzg4844" "github.com/ethereum/go-ethereum/event" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/metrics" @@ -1299,32 +1300,86 @@ func (p *BlobPool) GetMetadata(hash common.Hash) *txpool.TxMetadata { // GetBlobs returns a number of blobs and proofs for the given versioned hashes. // This is a utility method for the engine API, enabling consensus clients to // retrieve blobs from the pools directly instead of the network. -func (p *BlobPool) GetBlobs(vhashes []common.Hash) []*types.BlobTxSidecar { - sidecars := make([]*types.BlobTxSidecar, len(vhashes)) - for idx, vhash := range vhashes { - // Retrieve the datastore item (in a short lock) - p.lock.RLock() - id, exists := p.lookup.storeidOfBlob(vhash) - if !exists { - p.lock.RUnlock() - continue - } - data, err := p.store.Get(id) - p.lock.RUnlock() +func (p *BlobPool) GetBlobs(vhashes []common.Hash, version byte) ([]*kzg4844.Blob, []kzg4844.Commitment, [][]kzg4844.Proof, error) { + var ( + blobs = make([]*kzg4844.Blob, len(vhashes)) + commitments = make([]kzg4844.Commitment, len(vhashes)) + proofs = make([][]kzg4844.Proof, len(vhashes)) - // After releasing the lock, try to fill any blobs requested - if err != nil { - log.Error("Tracked blob transaction missing from store", "id", id, "err", err) - continue - } - item := new(types.Transaction) - if err = rlp.DecodeBytes(data, item); err != nil { - log.Error("Blobs corrupted for traced transaction", "id", id, "err", err) - continue - } - sidecars[idx] = item.BlobTxSidecar() + indices = make(map[common.Hash][]int) + filled = make(map[common.Hash]struct{}) + ) + for i, h := range vhashes { + indices[h] = append(indices[h], i) } - return sidecars + for _, vhash := range vhashes { + // Skip duplicate vhash that was already resolved in a previous iteration + if _, ok := filled[vhash]; ok { + continue + } + // Retrieve the corresponding blob tx with the vhash + p.lock.RLock() + txID, exists := p.lookup.storeidOfBlob(vhash) + p.lock.RUnlock() + if !exists { + return nil, nil, nil, fmt.Errorf("blob with vhash %x is not found", vhash) + } + data, err := p.store.Get(txID) + if err != nil { + return nil, nil, nil, err + } + + // Decode the blob transaction + tx := new(types.Transaction) + if err := rlp.DecodeBytes(data, tx); err != nil { + return nil, nil, nil, err + } + sidecar := tx.BlobTxSidecar() + if sidecar == nil { + return nil, nil, nil, fmt.Errorf("blob tx without sidecar %x", tx.Hash()) + } + // Traverse the blobs in the transaction + for i, hash := range tx.BlobHashes() { + list, ok := indices[hash] + if !ok { + continue // non-interesting blob + } + var pf []kzg4844.Proof + switch version { + case types.BlobSidecarVersion0: + if sidecar.Version == types.BlobSidecarVersion0 { + pf = []kzg4844.Proof{sidecar.Proofs[i]} + } else { + proof, err := kzg4844.ComputeBlobProof(&sidecar.Blobs[i], sidecar.Commitments[i]) + if err != nil { + return nil, nil, nil, err + } + pf = []kzg4844.Proof{proof} + } + case types.BlobSidecarVersion1: + if sidecar.Version == types.BlobSidecarVersion0 { + cellProofs, err := kzg4844.ComputeCellProofs(&sidecar.Blobs[i]) + if err != nil { + return nil, nil, nil, err + } + pf = cellProofs + } else { + cellProofs, err := sidecar.CellProofsAt(i) + if err != nil { + return nil, nil, nil, err + } + pf = cellProofs + } + } + for _, index := range list { + blobs[index] = &sidecar.Blobs[i] + commitments[index] = sidecar.Commitments[i] + proofs[index] = pf + } + filled[hash] = struct{}{} + } + } + return blobs, commitments, proofs, nil } // AvailableBlobs returns the number of blobs that are available in the subpool. diff --git a/core/txpool/blobpool/blobpool_test.go b/core/txpool/blobpool/blobpool_test.go index 422c35f6d2..55eed86cff 100644 --- a/core/txpool/blobpool/blobpool_test.go +++ b/core/txpool/blobpool/blobpool_test.go @@ -26,6 +26,7 @@ import ( "math/big" "os" "path/filepath" + "reflect" "sync" "testing" @@ -50,6 +51,7 @@ var ( testBlobCommits []kzg4844.Commitment testBlobProofs []kzg4844.Proof testBlobVHashes [][32]byte + testBlobIndices = make(map[[32]byte]int) ) const testMaxBlobsPerBlock = 6 @@ -66,6 +68,7 @@ func init() { testBlobProofs = append(testBlobProofs, testBlobProof) testBlobVHash := kzg4844.CalcBlobHashV1(sha256.New(), &testBlobCommit) + testBlobIndices[testBlobVHash] = len(testBlobVHashes) testBlobVHashes = append(testBlobVHashes, testBlobVHash) } } @@ -216,7 +219,7 @@ func makeTx(nonce uint64, gasTipCap uint64, gasFeeCap uint64, blobFeeCap uint64, // makeMultiBlobTx is a utility method to construct a ramdom blob tx with // certain number of blobs in its sidecar. -func makeMultiBlobTx(nonce uint64, gasTipCap uint64, gasFeeCap uint64, blobFeeCap uint64, blobCount int, key *ecdsa.PrivateKey) *types.Transaction { +func makeMultiBlobTx(nonce uint64, gasTipCap uint64, gasFeeCap uint64, blobFeeCap uint64, blobCount int, blobOffset int, key *ecdsa.PrivateKey, version byte) *types.Transaction { var ( blobs []kzg4844.Blob blobHashes []common.Hash @@ -224,10 +227,15 @@ func makeMultiBlobTx(nonce uint64, gasTipCap uint64, gasFeeCap uint64, blobFeeCa proofs []kzg4844.Proof ) for i := 0; i < blobCount; i++ { - blobs = append(blobs, *testBlobs[i]) - commitments = append(commitments, testBlobCommits[i]) - proofs = append(proofs, testBlobProofs[i]) - blobHashes = append(blobHashes, testBlobVHashes[i]) + blobs = append(blobs, *testBlobs[blobOffset+i]) + commitments = append(commitments, testBlobCommits[blobOffset+i]) + if version == types.BlobSidecarVersion0 { + proofs = append(proofs, testBlobProofs[blobOffset+i]) + } else { + cellProofs, _ := kzg4844.ComputeCellProofs(testBlobs[blobOffset+i]) + proofs = append(proofs, cellProofs...) + } + blobHashes = append(blobHashes, testBlobVHashes[blobOffset+i]) } blobtx := &types.BlobTx{ ChainID: uint256.MustFromBig(params.MainnetChainConfig.ChainID), @@ -238,7 +246,7 @@ func makeMultiBlobTx(nonce uint64, gasTipCap uint64, gasFeeCap uint64, blobFeeCa BlobFeeCap: uint256.NewInt(blobFeeCap), BlobHashes: blobHashes, Value: uint256.NewInt(100), - Sidecar: types.NewBlobTxSidecar(types.BlobSidecarVersion0, blobs, commitments, proofs), + Sidecar: types.NewBlobTxSidecar(version, blobs, commitments, proofs), } return types.MustSignNewTx(key, types.LatestSigner(params.MainnetChainConfig), blobtx) } @@ -396,35 +404,21 @@ func verifyPoolInternals(t *testing.T, pool *BlobPool) { // whatever is in the pool, it can be retrieved correctly. func verifyBlobRetrievals(t *testing.T, pool *BlobPool) { // Collect all the blobs tracked by the pool - known := make(map[common.Hash]struct{}) + var ( + hashes []common.Hash + known = make(map[common.Hash]struct{}) + ) for _, txs := range pool.index { for _, tx := range txs { for _, vhash := range tx.vhashes { known[vhash] = struct{}{} } + hashes = append(hashes, tx.vhashes...) } } - // Attempt to retrieve all test blobs - hashes := make([]common.Hash, len(testBlobVHashes)) - for i := range testBlobVHashes { - copy(hashes[i][:], testBlobVHashes[i][:]) - } - sidecars := pool.GetBlobs(hashes) - var blobs []*kzg4844.Blob - var proofs []*kzg4844.Proof - for idx, sidecar := range sidecars { - if sidecar == nil { - blobs = append(blobs, nil) - proofs = append(proofs, nil) - continue - } - blobHashes := sidecar.BlobHashes() - for i, hash := range blobHashes { - if hash == hashes[idx] { - blobs = append(blobs, &sidecar.Blobs[i]) - proofs = append(proofs, &sidecar.Proofs[i]) - } - } + blobs, _, proofs, err := pool.GetBlobs(hashes, types.BlobSidecarVersion0) + if err != nil { + t.Fatal(err) } // Cross validate what we received vs what we wanted if len(blobs) != len(hashes) || len(proofs) != len(hashes) { @@ -434,13 +428,12 @@ func verifyBlobRetrievals(t *testing.T, pool *BlobPool) { for i, hash := range hashes { // If an item is missing, but shouldn't, error if blobs[i] == nil || proofs[i] == nil { - if _, ok := known[hash]; ok { - t.Errorf("tracked blob retrieval failed: item %d, hash %x", i, hash) - } + t.Errorf("tracked blob retrieval failed: item %d, hash %x", i, hash) continue } // Item retrieved, make sure it matches the expectation - if *blobs[i] != *testBlobs[i] || *proofs[i] != testBlobProofs[i] { + index := testBlobIndices[hash] + if *blobs[i] != *testBlobs[index] || proofs[i][0] != testBlobProofs[index] { t.Errorf("retrieved blob or proof mismatch: item %d, hash %x", i, hash) continue } @@ -1071,9 +1064,9 @@ func TestChangingSlotterSize(t *testing.T) { addr2 = crypto.PubkeyToAddress(key2.PublicKey) addr3 = crypto.PubkeyToAddress(key3.PublicKey) - tx1 = makeMultiBlobTx(0, 1, 1000, 100, 6, key1) - tx2 = makeMultiBlobTx(0, 1, 800, 70, 6, key2) - tx3 = makeMultiBlobTx(0, 1, 800, 110, 24, key3) + tx1 = makeMultiBlobTx(0, 1, 1000, 100, 6, 0, key1, types.BlobSidecarVersion0) + tx2 = makeMultiBlobTx(0, 1, 800, 70, 6, 0, key2, types.BlobSidecarVersion0) + tx3 = makeMultiBlobTx(0, 1, 800, 110, 24, 0, key3, types.BlobSidecarVersion0) blob1, _ = rlp.EncodeToBytes(tx1) blob2, _ = rlp.EncodeToBytes(tx2) @@ -1191,8 +1184,8 @@ func TestBlobCountLimit(t *testing.T) { // Attempt to add transactions. var ( - tx1 = makeMultiBlobTx(0, 1, 1000, 100, 6, key1) - tx2 = makeMultiBlobTx(0, 1, 800, 70, 7, key2) + tx1 = makeMultiBlobTx(0, 1, 1000, 100, 6, 0, key1, types.BlobSidecarVersion0) + tx2 = makeMultiBlobTx(0, 1, 800, 70, 7, 0, key2, types.BlobSidecarVersion0) ) errs := pool.Add([]*types.Transaction{tx1, tx2}, true) @@ -1675,6 +1668,181 @@ func TestAdd(t *testing.T) { } } +func TestGetBlobs(t *testing.T) { + //log.SetDefault(log.NewLogger(log.NewTerminalHandlerWithLevel(os.Stderr, log.LevelTrace, true))) + + // Create a temporary folder for the persistent backend + storage := t.TempDir() + + os.MkdirAll(filepath.Join(storage, pendingTransactionStore), 0700) + store, _ := billy.Open(billy.Options{Path: filepath.Join(storage, pendingTransactionStore)}, newSlotter(params.BlobTxMaxBlobs), nil) + + // Create transactions from a few accounts. + var ( + key1, _ = crypto.GenerateKey() + key2, _ = crypto.GenerateKey() + key3, _ = crypto.GenerateKey() + + addr1 = crypto.PubkeyToAddress(key1.PublicKey) + addr2 = crypto.PubkeyToAddress(key2.PublicKey) + addr3 = crypto.PubkeyToAddress(key3.PublicKey) + + tx1 = makeMultiBlobTx(0, 1, 1000, 100, 6, 0, key1, types.BlobSidecarVersion0) // [0, 6) + tx2 = makeMultiBlobTx(0, 1, 800, 70, 6, 6, key2, types.BlobSidecarVersion1) // [6, 12) + tx3 = makeMultiBlobTx(0, 1, 800, 110, 6, 12, key3, types.BlobSidecarVersion0) // [12, 18) + + blob1, _ = rlp.EncodeToBytes(tx1) + blob2, _ = rlp.EncodeToBytes(tx2) + blob3, _ = rlp.EncodeToBytes(tx3) + ) + + // Write the two safely sized txs to store. note: although the store is + // configured for a blob count of 6, it can also support around ~1mb of call + // data - all this to say that we aren't using the the absolute largest shelf + // available. + store.Put(blob1) + store.Put(blob2) + store.Put(blob3) + store.Close() + + // Mimic a blobpool with max blob count of 6 upgrading to a max blob count of 24. + statedb, _ := state.New(types.EmptyRootHash, state.NewDatabaseForTesting()) + statedb.AddBalance(addr1, uint256.NewInt(1_000_000_000), tracing.BalanceChangeUnspecified) + statedb.AddBalance(addr2, uint256.NewInt(1_000_000_000), tracing.BalanceChangeUnspecified) + statedb.AddBalance(addr3, uint256.NewInt(1_000_000_000), tracing.BalanceChangeUnspecified) + statedb.Commit(0, true, false) + + // Make custom chain config where the max blob count changes based on the loop variable. + cancunTime := uint64(0) + config := ¶ms.ChainConfig{ + ChainID: big.NewInt(1), + LondonBlock: big.NewInt(0), + BerlinBlock: big.NewInt(0), + CancunTime: &cancunTime, + BlobScheduleConfig: ¶ms.BlobScheduleConfig{ + Cancun: ¶ms.BlobConfig{ + Target: 12, + Max: 24, + UpdateFraction: params.DefaultCancunBlobConfig.UpdateFraction, + }, + }, + } + chain := &testBlockChain{ + config: config, + basefee: uint256.NewInt(1050), + blobfee: uint256.NewInt(105), + statedb: statedb, + } + pool := New(Config{Datadir: storage}, chain, nil) + if err := pool.Init(1, chain.CurrentBlock(), newReserver()); err != nil { + t.Fatalf("failed to create blob pool: %v", err) + } + + // Verify the regular three txs are always available. + if got := pool.Get(tx1.Hash()); got == nil { + t.Errorf("expected tx %s from %s in pool", tx1.Hash(), addr1) + } + if got := pool.Get(tx2.Hash()); got == nil { + t.Errorf("expected tx %s from %s in pool", tx2.Hash(), addr2) + } + if got := pool.Get(tx3.Hash()); got == nil { + t.Errorf("expected tx %s from %s in pool", tx3.Hash(), addr3) + } + + cases := []struct { + start int + limit int + version byte + expErr bool + }{ + { + start: 0, limit: 6, + version: types.BlobSidecarVersion0, + }, + { + start: 0, limit: 6, + version: types.BlobSidecarVersion1, + }, + { + start: 3, limit: 9, + version: types.BlobSidecarVersion0, + }, + { + start: 3, limit: 9, + version: types.BlobSidecarVersion1, + }, + { + start: 3, limit: 15, + version: types.BlobSidecarVersion0, + }, + { + start: 3, limit: 15, + version: types.BlobSidecarVersion1, + }, + { + start: 0, limit: 18, + version: types.BlobSidecarVersion0, + }, + { + start: 0, limit: 18, + version: types.BlobSidecarVersion1, + }, + { + start: 18, limit: 20, + version: types.BlobSidecarVersion0, + expErr: true, + }, + } + for i, c := range cases { + var vhashes []common.Hash + for j := c.start; j < c.limit; j++ { + vhashes = append(vhashes, testBlobVHashes[j]) + } + blobs, _, proofs, err := pool.GetBlobs(vhashes, c.version) + + if c.expErr { + if err == nil { + t.Errorf("Unexpected return, want error for case %d", i) + } + } else { + if err != nil { + t.Errorf("Unexpected error for case %d, %v", i, err) + } + // Cross validate what we received vs what we wanted + length := c.limit - c.start + if len(blobs) != length || len(proofs) != length { + t.Errorf("retrieved blobs/proofs size mismatch: have %d/%d, want %d", len(blobs), len(proofs), length) + continue + } + for j := 0; j < len(blobs); j++ { + // If an item is missing, but shouldn't, error + if blobs[j] == nil || proofs[j] == nil { + t.Errorf("tracked blob retrieval failed: item %d, hash %x", j, vhashes[j]) + continue + } + // Item retrieved, make sure the blob matches the expectation + if *blobs[j] != *testBlobs[c.start+j] { + t.Errorf("retrieved blob mismatch: item %d, hash %x", j, vhashes[j]) + continue + } + // Item retrieved, make sure the proof matches the expectation + if c.version == types.BlobSidecarVersion0 { + if proofs[j][0] != testBlobProofs[c.start+j] { + t.Errorf("retrieved proof mismatch: item %d, hash %x", j, vhashes[j]) + } + } else { + want, _ := kzg4844.ComputeCellProofs(blobs[j]) + if !reflect.DeepEqual(want, proofs[j]) { + t.Errorf("retrieved proof mismatch: item %d, hash %x", j, vhashes[j]) + } + } + } + } + } + + pool.Close() +} + // fakeBilly is a billy.Database implementation which just drops data on the floor. type fakeBilly struct { billy.Database diff --git a/eth/catalyst/api.go b/eth/catalyst/api.go index f91896cc6e..038328d9ba 100644 --- a/eth/catalyst/api.go +++ b/eth/catalyst/api.go @@ -18,7 +18,6 @@ package catalyst import ( - "crypto/sha256" "errors" "fmt" "strconv" @@ -31,7 +30,6 @@ import ( "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/kzg4844" "github.com/ethereum/go-ethereum/eth" "github.com/ethereum/go-ethereum/eth/ethconfig" "github.com/ethereum/go-ethereum/internal/version" @@ -120,10 +118,13 @@ var caps = []string{ var ( // Number of blobs requested via getBlobsV2 getBlobsRequestedCounter = metrics.NewRegisteredCounter("engine/getblobs/requested", nil) + // Number of blobs requested via getBlobsV2 that are present in the blobpool getBlobsAvailableCounter = metrics.NewRegisteredCounter("engine/getblobs/available", nil) + // Number of times getBlobsV2 responded with “hit” getBlobsV2RequestHit = metrics.NewRegisteredCounter("engine/getblobs/hit", nil) + // Number of times getBlobsV2 responded with “miss” getBlobsV2RequestMiss = metrics.NewRegisteredCounter("engine/getblobs/miss", nil) ) @@ -494,29 +495,15 @@ func (api *ConsensusAPI) GetBlobsV1(hashes []common.Hash) ([]*engine.BlobAndProo if len(hashes) > 128 { return nil, engine.TooLargeRequest.With(fmt.Errorf("requested blob count too large: %v", len(hashes))) } - var ( - res = make([]*engine.BlobAndProofV1, len(hashes)) - hasher = sha256.New() - index = make(map[common.Hash]int) - sidecars = api.eth.BlobTxPool().GetBlobs(hashes) - ) - - for i, hash := range hashes { - index[hash] = i + blobs, _, proofs, err := api.eth.BlobTxPool().GetBlobs(hashes, types.BlobSidecarVersion0) + if err != nil { + return nil, engine.InvalidParams.With(err) } - for i, sidecar := range sidecars { - if res[i] != nil || sidecar == nil { - // already filled - continue - } - for cIdx, commitment := range sidecar.Commitments { - computed := kzg4844.CalcBlobHashV1(hasher, &commitment) - if idx, ok := index[computed]; ok { - res[idx] = &engine.BlobAndProofV1{ - Blob: sidecar.Blobs[cIdx][:], - Proof: sidecar.Proofs[cIdx][:], - } - } + res := make([]*engine.BlobAndProofV1, len(hashes)) + for i := 0; i < len(blobs); i++ { + res[i] = &engine.BlobAndProofV1{ + Blob: blobs[i][:], + Proof: proofs[i][0][:], } } return res, nil @@ -538,47 +525,19 @@ func (api *ConsensusAPI) GetBlobsV2(hashes []common.Hash) ([]*engine.BlobAndProo } getBlobsV2RequestHit.Inc(1) - // pull up the blob hashes - var ( - res = make([]*engine.BlobAndProofV2, len(hashes)) - index = make(map[common.Hash][]int) - sidecars = api.eth.BlobTxPool().GetBlobs(hashes) - ) - - for i, hash := range hashes { - index[hash] = append(index[hash], i) + blobs, _, proofs, err := api.eth.BlobTxPool().GetBlobs(hashes, types.BlobSidecarVersion1) + if err != nil { + return nil, engine.InvalidParams.With(err) } - for i, sidecar := range sidecars { - if res[i] != nil { - // already filled - continue + res := make([]*engine.BlobAndProofV2, len(hashes)) + for i := 0; i < len(blobs); i++ { + var cellProofs []hexutil.Bytes + for _, proof := range proofs[i] { + cellProofs = append(cellProofs, proof[:]) } - if sidecar == nil { - // not found, return empty response - return nil, nil - } - if sidecar.Version != types.BlobSidecarVersion1 { - log.Info("GetBlobs queried V0 transaction: index %v, blobhashes %v", index, sidecar.BlobHashes()) - return nil, nil - } - blobHashes := sidecar.BlobHashes() - for bIdx, hash := range blobHashes { - if idxes, ok := index[hash]; ok { - proofs, err := sidecar.CellProofsAt(bIdx) - if err != nil { - return nil, engine.InvalidParams.With(err) - } - var cellProofs []hexutil.Bytes - for _, proof := range proofs { - cellProofs = append(cellProofs, proof[:]) - } - for _, idx := range idxes { - res[idx] = &engine.BlobAndProofV2{ - Blob: sidecar.Blobs[bIdx][:], - CellProofs: cellProofs, - } - } - } + res[i] = &engine.BlobAndProofV2{ + Blob: blobs[i][:], + CellProofs: cellProofs, } } return res, nil From 59405c40d394552f1915caedd5f43d971c7ba1fd Mon Sep 17 00:00:00 2001 From: Minhyuk Kim Date: Tue, 5 Aug 2025 20:51:16 +0900 Subject: [PATCH 16/57] eth/gasestimator: check ErrGasLimitTooHigh conditions (#32348) This PR makes 2 changes to how [EIP-7825](https://github.com/ethereum/go-ethereum/pull/31824) behaves. When `eth_estimateGas` or `eth_createAccessList` is called without any gas limit in the payload, geth will choose the block's gas limit or the `RPCGasCap`, which can be larger than the `maxTxGas`. When this happens for `estimateGas`, the gas estimation just errors out and ends, when it should continue doing binary search to find the lowest possible gas limit. This PR will: - Add a check to see if `hi` is larger than `maxTxGas` and cap it to `maxTxGas` if it's larger. And add a special case handling for gas estimation execute when it errs with `ErrGasLimitTooHigh` --------- Co-authored-by: Gary Rong --- eth/gasestimator/gasestimator.go | 20 ++++++++++++++++++++ internal/ethapi/override/override_test.go | 4 ++++ 2 files changed, 24 insertions(+) diff --git a/eth/gasestimator/gasestimator.go b/eth/gasestimator/gasestimator.go index 7e9d8125de..6e79fbd62b 100644 --- a/eth/gasestimator/gasestimator.go +++ b/eth/gasestimator/gasestimator.go @@ -62,6 +62,23 @@ func Estimate(ctx context.Context, call *core.Message, opts *Options, gasCap uin if call.GasLimit >= params.TxGas { hi = call.GasLimit } + + // Cap the maximum gas allowance according to EIP-7825 if the estimation targets Osaka + if hi > params.MaxTxGas { + blockNumber, blockTime := opts.Header.Number, opts.Header.Time + if opts.BlockOverrides != nil { + if opts.BlockOverrides.Number != nil { + blockNumber = opts.BlockOverrides.Number.ToInt() + } + if opts.BlockOverrides.Time != nil { + blockTime = uint64(*opts.BlockOverrides.Time) + } + } + if opts.Config.IsOsaka(blockNumber, blockTime) { + hi = params.MaxTxGas + } + } + // Normalize the max fee per gas the call is willing to spend. var feeCap *big.Int if call.GasFeeCap != nil { @@ -209,6 +226,9 @@ func execute(ctx context.Context, call *core.Message, opts *Options, gasLimit ui if errors.Is(err, core.ErrIntrinsicGas) { return true, nil, nil // Special case, raise gas limit } + if errors.Is(err, core.ErrGasLimitTooHigh) { + return true, nil, nil // Special case, lower gas limit + } return true, nil, err // Bail out } return result.Failed(), result, nil diff --git a/internal/ethapi/override/override_test.go b/internal/ethapi/override/override_test.go index 02a17c1331..41b4f2c253 100644 --- a/internal/ethapi/override/override_test.go +++ b/internal/ethapi/override/override_test.go @@ -31,6 +31,10 @@ import ( type precompileContract struct{} +func (p *precompileContract) Name() string { + panic("implement me") +} + func (p *precompileContract) RequiredGas(input []byte) uint64 { return 0 } func (p *precompileContract) Run(input []byte) ([]byte, error) { return nil, nil } From 792de5d2e3b40837aadb65993e387bf5aa5bce9f Mon Sep 17 00:00:00 2001 From: cui Date: Wed, 6 Aug 2025 18:57:43 +0800 Subject: [PATCH 17/57] core/filtermaps: remove unnecessary nil check and add cv2 lock (#32309) Co-authored-by: zsfelfoldi --- core/filtermaps/chain_view.go | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) diff --git a/core/filtermaps/chain_view.go b/core/filtermaps/chain_view.go index 7c48048ad9..35c5ed22a5 100644 --- a/core/filtermaps/chain_view.go +++ b/core/filtermaps/chain_view.go @@ -124,19 +124,12 @@ func (cv *ChainView) RawReceipts(number uint64) types.Receipts { // SharedRange returns the block range shared by two chain views. func (cv *ChainView) SharedRange(cv2 *ChainView) common.Range[uint64] { - cv.lock.Lock() - defer cv.lock.Unlock() - - if cv == nil || cv2 == nil || !cv.extendNonCanonical() || !cv2.extendNonCanonical() { + if cv == nil || cv2 == nil { return common.Range[uint64]{} } - var sharedLen uint64 - for n := min(cv.headNumber+1-uint64(len(cv.hashes)), cv2.headNumber+1-uint64(len(cv2.hashes))); n <= cv.headNumber && n <= cv2.headNumber; n++ { - h1, h2 := cv.blockHash(n), cv2.blockHash(n) - if h1 != h2 || h1 == (common.Hash{}) { - break - } - sharedLen = n + 1 + sharedLen := min(cv.headNumber, cv2.headNumber) + 1 + for sharedLen > 0 && cv.BlockId(sharedLen-1) != cv2.BlockId(sharedLen-1) { + sharedLen-- } return common.NewRange(0, sharedLen) } From e7189b59871931cb15747db376ce7dcc595f7f9a Mon Sep 17 00:00:00 2001 From: cui Date: Thu, 7 Aug 2025 16:42:22 +0800 Subject: [PATCH 18/57] go.mod: upgraded github.com/golang-jwt/jwt/v4 v4.5.1 => v4.5.2 (#32356) https://pkg.go.dev/vuln/GO-2025-3553 --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 6b63450a91..363d7d3dfb 100644 --- a/go.mod +++ b/go.mod @@ -29,7 +29,7 @@ require ( github.com/fsnotify/fsnotify v1.6.0 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.1 + github.com/golang-jwt/jwt/v4 v4.5.2 github.com/golang/snappy v0.0.5-0.20220116011046-fa5810519dcb github.com/google/gofuzz v1.2.0 github.com/google/uuid v1.3.0 diff --git a/go.sum b/go.sum index db59c74229..099d432ba4 100644 --- a/go.sum +++ b/go.sum @@ -148,8 +148,8 @@ github.com/gofrs/flock v0.12.1 h1:MTLVXXHf8ekldpJk3AKicLij9MdwOWkZ+a/jHHZby9E= github.com/gofrs/flock v0.12.1/go.mod h1:9zxTsyu5xtJ9DK+1tFZyibEV7y3uwDxPPfbxeeHCoD0= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= -github.com/golang-jwt/jwt/v4 v4.5.1 h1:JdqV9zKUdtaa9gdPlywC3aeoEsR681PlKC+4F5gQgeo= -github.com/golang-jwt/jwt/v4 v4.5.1/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= +github.com/golang-jwt/jwt/v4 v4.5.2 h1:YtQM7lnr8iZ+j5q71MGKkNw9Mn7AjHM68uc9g5fXeUI= +github.com/golang-jwt/jwt/v4 v4.5.2/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= From f49f3ec78086903b278559f29bf38124c02d825f Mon Sep 17 00:00:00 2001 From: cui Date: Thu, 7 Aug 2025 20:15:54 +0800 Subject: [PATCH 19/57] rpc: use reflect.TypeFor (#32316) --- rpc/service.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/rpc/service.go b/rpc/service.go index d50090e9fb..0f62d7eb7c 100644 --- a/rpc/service.go +++ b/rpc/service.go @@ -29,10 +29,10 @@ import ( ) var ( - contextType = reflect.TypeOf((*context.Context)(nil)).Elem() - errorType = reflect.TypeOf((*error)(nil)).Elem() - subscriptionType = reflect.TypeOf(Subscription{}) - stringType = reflect.TypeOf("") + contextType = reflect.TypeFor[context.Context]() + errorType = reflect.TypeFor[error]() + subscriptionType = reflect.TypeFor[Subscription]() + stringType = reflect.TypeFor[string]() ) type serviceRegistry struct { From dfde155541f82f4b8f3bf72ee507a12e716dde21 Mon Sep 17 00:00:00 2001 From: cui Date: Thu, 7 Aug 2025 20:22:11 +0800 Subject: [PATCH 20/57] crypto/kzg4844: use reflect.TypeFor (#32319) --- crypto/kzg4844/kzg4844.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/crypto/kzg4844/kzg4844.go b/crypto/kzg4844/kzg4844.go index baf9c9655b..9da2386368 100644 --- a/crypto/kzg4844/kzg4844.go +++ b/crypto/kzg4844/kzg4844.go @@ -31,9 +31,9 @@ import ( var content embed.FS var ( - blobT = reflect.TypeOf(Blob{}) - commitmentT = reflect.TypeOf(Commitment{}) - proofT = reflect.TypeOf(Proof{}) + blobT = reflect.TypeFor[Blob]() + commitmentT = reflect.TypeFor[Commitment]() + proofT = reflect.TypeFor[Proof]() CellProofsPerBlob = 128 ) From ec97ac70851c81962a1b999e01b339a3348d6892 Mon Sep 17 00:00:00 2001 From: cui Date: Thu, 7 Aug 2025 20:30:03 +0800 Subject: [PATCH 21/57] common, common/hexutil: use reflect.TypeFor (#32321) --- common/hexutil/json.go | 10 +++++----- common/types.go | 6 +++--- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/common/hexutil/json.go b/common/hexutil/json.go index e0ac98f52d..6b9f412078 100644 --- a/common/hexutil/json.go +++ b/common/hexutil/json.go @@ -28,11 +28,11 @@ import ( ) var ( - bytesT = reflect.TypeOf(Bytes(nil)) - bigT = reflect.TypeOf((*Big)(nil)) - uintT = reflect.TypeOf(Uint(0)) - uint64T = reflect.TypeOf(Uint64(0)) - u256T = reflect.TypeOf((*uint256.Int)(nil)) + bytesT = reflect.TypeFor[Bytes]() + bigT = reflect.TypeFor[*Big]() + uintT = reflect.TypeFor[Uint]() + uint64T = reflect.TypeFor[Uint64]() + u256T = reflect.TypeFor[*uint256.Int]() ) // Bytes marshals/unmarshals as a JSON string with 0x prefix. diff --git a/common/types.go b/common/types.go index fdb25f1b34..db4de8bcbd 100644 --- a/common/types.go +++ b/common/types.go @@ -42,8 +42,8 @@ const ( ) var ( - hashT = reflect.TypeOf(Hash{}) - addressT = reflect.TypeOf(Address{}) + hashT = reflect.TypeFor[Hash]() + addressT = reflect.TypeFor[Address]() // MaxAddress represents the maximum possible address value. MaxAddress = HexToAddress("0xffffffffffffffffffffffffffffffffffffffff") @@ -466,7 +466,7 @@ func isString(input []byte) bool { // UnmarshalJSON parses a hash in hex syntax. func (d *Decimal) UnmarshalJSON(input []byte) error { if !isString(input) { - return &json.UnmarshalTypeError{Value: "non-string", Type: reflect.TypeOf(uint64(0))} + return &json.UnmarshalTypeError{Value: "non-string", Type: reflect.TypeFor[uint64]()} } if i, err := strconv.ParseUint(string(input[1:len(input)-1]), 10, 64); err == nil { *d = Decimal(i) From 2e3971aed1fbdfed9013611140d8afaf68eed8ff Mon Sep 17 00:00:00 2001 From: cui Date: Thu, 7 Aug 2025 20:36:20 +0800 Subject: [PATCH 22/57] beacon/merkle: use reflect.TypeFor (#32322) --- beacon/merkle/merkle.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/beacon/merkle/merkle.go b/beacon/merkle/merkle.go index 30896f9b01..64dfadfab5 100644 --- a/beacon/merkle/merkle.go +++ b/beacon/merkle/merkle.go @@ -32,7 +32,7 @@ type Value [32]byte // Values represent a series of merkle tree leaves/nodes. type Values []Value -var valueT = reflect.TypeOf(Value{}) +var valueT = reflect.TypeFor[Value]() // UnmarshalJSON parses a merkle value in hex syntax. func (m *Value) UnmarshalJSON(input []byte) error { From f9f85d0227078397eb293579081ec98753f8e4c5 Mon Sep 17 00:00:00 2001 From: cui Date: Thu, 7 Aug 2025 20:53:36 +0800 Subject: [PATCH 23/57] core: use reflect.TypeFor (#32320) https://github.com/golang/go/issues/60088 --- core/forkid/forkid.go | 7 +++---- core/tracing/journal_test.go | 2 +- core/types/block.go | 2 +- core/types/withdrawal.go | 2 +- 4 files changed, 6 insertions(+), 7 deletions(-) diff --git a/core/forkid/forkid.go b/core/forkid/forkid.go index 4db366da82..7406a3f53a 100644 --- a/core/forkid/forkid.go +++ b/core/forkid/forkid.go @@ -241,9 +241,8 @@ func checksumToBytes(hash uint32) [4]byte { // them, one for the block number based forks and the second for the timestamps. func gatherForks(config *params.ChainConfig, genesis uint64) ([]uint64, []uint64) { // Gather all the fork block numbers via reflection - kind := reflect.TypeOf(params.ChainConfig{}) + kind := reflect.TypeFor[params.ChainConfig]() conf := reflect.ValueOf(config).Elem() - x := uint64(0) var ( forksByBlock []uint64 forksByTime []uint64 @@ -258,12 +257,12 @@ func gatherForks(config *params.ChainConfig, genesis uint64) ([]uint64, []uint64 } // Extract the fork rule block number or timestamp and aggregate it - if field.Type == reflect.TypeOf(&x) { + if field.Type == reflect.TypeFor[*uint64]() { if rule := conf.Field(i).Interface().(*uint64); rule != nil { forksByTime = append(forksByTime, *rule) } } - if field.Type == reflect.TypeOf(new(big.Int)) { + if field.Type == reflect.TypeFor[*big.Int]() { if rule := conf.Field(i).Interface().(*big.Int); rule != nil { forksByBlock = append(forksByBlock, rule.Uint64()) } diff --git a/core/tracing/journal_test.go b/core/tracing/journal_test.go index d9616a2ce8..99447e1e1d 100644 --- a/core/tracing/journal_test.go +++ b/core/tracing/journal_test.go @@ -293,7 +293,7 @@ func newTracerAllHooks() *tracerAllHooks { t := &tracerAllHooks{hooksCalled: make(map[string]bool)} // Initialize all hooks to false. We will use this to // get total count of hooks. - hooksType := reflect.TypeOf((*Hooks)(nil)).Elem() + hooksType := reflect.TypeFor[Hooks]() for i := 0; i < hooksType.NumField(); i++ { t.hooksCalled[hooksType.Field(i).Name] = false } diff --git a/core/types/block.go b/core/types/block.go index b284fb3b16..da9614793a 100644 --- a/core/types/block.go +++ b/core/types/block.go @@ -128,7 +128,7 @@ func (h *Header) Hash() common.Hash { return rlpHash(h) } -var headerSize = common.StorageSize(reflect.TypeOf(Header{}).Size()) +var headerSize = common.StorageSize(reflect.TypeFor[Header]().Size()) // Size returns the approximate memory used by all internal contents. It is used // to approximate and limit the memory consumption of various caches. diff --git a/core/types/withdrawal.go b/core/types/withdrawal.go index 6f99e53b56..2cf00195a0 100644 --- a/core/types/withdrawal.go +++ b/core/types/withdrawal.go @@ -49,7 +49,7 @@ type Withdrawals []*Withdrawal // Len returns the length of s. func (s Withdrawals) Len() int { return len(s) } -var withdrawalSize = int(reflect.TypeOf(Withdrawal{}).Size()) +var withdrawalSize = int(reflect.TypeFor[Withdrawal]().Size()) func (s Withdrawals) Size() int { return withdrawalSize * len(s) From e979438a55739169dc6ab2ca0f2da668888a76d6 Mon Sep 17 00:00:00 2001 From: cui Date: Thu, 7 Aug 2025 21:03:18 +0800 Subject: [PATCH 24/57] p2p/enode: use atomic.Pointer in LocalNode (#32360) --- p2p/enode/localnode.go | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/p2p/enode/localnode.go b/p2p/enode/localnode.go index 6e79c9cbdc..d8fa6a9202 100644 --- a/p2p/enode/localnode.go +++ b/p2p/enode/localnode.go @@ -45,7 +45,7 @@ const ( // current process. Setting ENR entries via the Set method updates the record. A new version // of the record is signed on demand when the Node method is called. type LocalNode struct { - cur atomic.Value // holds a non-nil node pointer while the record is up-to-date + cur atomic.Pointer[Node] // holds a non-nil node pointer while the record is up-to-date id ID key *ecdsa.PrivateKey @@ -82,7 +82,7 @@ func NewLocalNode(db *DB, key *ecdsa.PrivateKey) *LocalNode { } ln.seq = db.localSeq(ln.id) ln.update = time.Now() - ln.cur.Store((*Node)(nil)) + ln.cur.Store(nil) return ln } @@ -94,7 +94,7 @@ func (ln *LocalNode) Database() *DB { // Node returns the current version of the local node record. func (ln *LocalNode) Node() *Node { // If we have a valid record, return that - n := ln.cur.Load().(*Node) + n := ln.cur.Load() if n != nil { return n } @@ -105,7 +105,7 @@ func (ln *LocalNode) Node() *Node { // Double check the current record, since multiple goroutines might be waiting // on the write mutex. - if n = ln.cur.Load().(*Node); n != nil { + if n = ln.cur.Load(); n != nil { return n } @@ -121,7 +121,7 @@ func (ln *LocalNode) Node() *Node { ln.sign() ln.update = time.Now() - return ln.cur.Load().(*Node) + return ln.cur.Load() } // Seq returns the current sequence number of the local node record. @@ -276,11 +276,11 @@ func (e *lnEndpoint) get() (newIP net.IP, newPort uint16) { } func (ln *LocalNode) invalidate() { - ln.cur.Store((*Node)(nil)) + ln.cur.Store(nil) } func (ln *LocalNode) sign() { - if n := ln.cur.Load().(*Node); n != nil { + if n := ln.cur.Load(); n != nil { return // no changes } From bd6797eafa592472a5b6b495ed3a1a68c022f013 Mon Sep 17 00:00:00 2001 From: cui Date: Thu, 7 Aug 2025 21:56:25 +0800 Subject: [PATCH 25/57] signer/core/apitypes: simplify reflect []byte creation (#32315) Co-authored-by: Felix Lange --- signer/core/apitypes/types.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/signer/core/apitypes/types.go b/signer/core/apitypes/types.go index b5fd5a2854..dcbd04867c 100644 --- a/signer/core/apitypes/types.go +++ b/signer/core/apitypes/types.go @@ -544,7 +544,7 @@ func parseBytes(encType interface{}) ([]byte, bool) { // Handle array types. val := reflect.ValueOf(encType) if val.Kind() == reflect.Array && val.Type().Elem().Kind() == reflect.Uint8 { - v := reflect.MakeSlice(reflect.TypeOf([]byte{}), val.Len(), val.Len()) + v := reflect.ValueOf(make([]byte, val.Len())) reflect.Copy(v, val) return v.Bytes(), true } From 4e7bc2bdc89e1fa27d259ef3efe7a59d2d2142d2 Mon Sep 17 00:00:00 2001 From: cui Date: Thu, 7 Aug 2025 21:58:27 +0800 Subject: [PATCH 26/57] rlp: use reflect.TypeFor (#32317) Co-authored-by: Felix Lange --- rlp/decode.go | 8 ++++---- rlp/encode.go | 2 +- rlp/raw.go | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/rlp/decode.go b/rlp/decode.go index 0fbca243ee..5a06f35ec0 100644 --- a/rlp/decode.go +++ b/rlp/decode.go @@ -148,9 +148,9 @@ func addErrorContext(err error, ctx string) error { } var ( - decoderInterface = reflect.TypeOf(new(Decoder)).Elem() - bigInt = reflect.TypeOf(big.Int{}) - u256Int = reflect.TypeOf(uint256.Int{}) + decoderInterface = reflect.TypeFor[Decoder]() + bigInt = reflect.TypeFor[big.Int]() + u256Int = reflect.TypeFor[uint256.Int]() ) func makeDecoder(typ reflect.Type, tags rlpstruct.Tags) (dec decoder, err error) { @@ -512,7 +512,7 @@ func makeNilPtrDecoder(etype reflect.Type, etypeinfo *typeinfo, ts rlpstruct.Tag } } -var ifsliceType = reflect.TypeOf([]interface{}{}) +var ifsliceType = reflect.TypeFor[[]any]() func decodeInterface(s *Stream, val reflect.Value) error { if val.Type().NumMethod() != 0 { diff --git a/rlp/encode.go b/rlp/encode.go index 3645bbfda0..623932a90b 100644 --- a/rlp/encode.go +++ b/rlp/encode.go @@ -133,7 +133,7 @@ func puthead(buf []byte, smalltag, largetag byte, size uint64) int { return sizesize + 1 } -var encoderInterface = reflect.TypeOf(new(Encoder)).Elem() +var encoderInterface = reflect.TypeFor[Encoder]() // makeWriter creates a writer function for the given type. func makeWriter(typ reflect.Type, ts rlpstruct.Tags) (writer, error) { diff --git a/rlp/raw.go b/rlp/raw.go index 879e3bfe5d..cec90346a1 100644 --- a/rlp/raw.go +++ b/rlp/raw.go @@ -26,7 +26,7 @@ import ( // not verify whether the content of RawValues is valid RLP. type RawValue []byte -var rawValueType = reflect.TypeOf(RawValue{}) +var rawValueType = reflect.TypeFor[RawValue]() // StringSize returns the encoded size of a string. func StringSize(s string) uint64 { From f86870f5da77e2563fdb7151078be24c12fa2076 Mon Sep 17 00:00:00 2001 From: radik878 Date: Thu, 7 Aug 2025 17:31:02 +0300 Subject: [PATCH 27/57] eth/downloader: fix incomplete code comment (#32354) --- eth/downloader/api.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/eth/downloader/api.go b/eth/downloader/api.go index c98f9a2c3f..f97371de5f 100644 --- a/eth/downloader/api.go +++ b/eth/downloader/api.go @@ -200,7 +200,7 @@ func (s *SyncStatusSubscription) Unsubscribe() { } // SubscribeSyncStatus creates a subscription that will broadcast new synchronisation updates. -// The given channel must receive interface values, the result can either. +// The given channel must receive interface values, the result can either be a SyncingResult or false. func (api *DownloaderAPI) SubscribeSyncStatus(status chan interface{}) *SyncStatusSubscription { api.installSyncSubscription <- status return &SyncStatusSubscription{api: api, c: status} From 888b71b3cfa4a7daf152bae930a2afdf8edee6ce Mon Sep 17 00:00:00 2001 From: cui Date: Fri, 8 Aug 2025 02:03:30 +0800 Subject: [PATCH 28/57] metrics: use atomic.Pointer in runtimeHistogram (#32361) Co-authored-by: Felix Lange --- metrics/runtimehistogram.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/metrics/runtimehistogram.go b/metrics/runtimehistogram.go index 53904b2b28..0ab8914602 100644 --- a/metrics/runtimehistogram.go +++ b/metrics/runtimehistogram.go @@ -14,7 +14,7 @@ func getOrRegisterRuntimeHistogram(name string, scale float64, r Registry) *runt // runtimeHistogram wraps a runtime/metrics histogram. type runtimeHistogram struct { - v atomic.Value // v is a pointer to a metrics.Float64Histogram + v atomic.Pointer[metrics.Float64Histogram] scaleFactor float64 } @@ -58,7 +58,7 @@ func (h *runtimeHistogram) Update(int64) { // Snapshot returns a non-changing copy of the histogram. func (h *runtimeHistogram) Snapshot() HistogramSnapshot { - hist := h.v.Load().(*metrics.Float64Histogram) + hist := h.v.Load() return newRuntimeHistogramSnapshot(hist) } From c3ef6c77c24956ebe1156205869259ffb8892486 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=96mer=20Faruk=20Irmak?= Date: Fri, 8 Aug 2025 01:01:41 +0300 Subject: [PATCH 29/57] core/vm: fold EVMInterpreter into EVM (#32352) The separation serves no purpose atm, and the circular dependency that EVM and EVMInterpreter had was begging for them to be merged. --- core/vm/eips.go | 58 ++--- core/vm/evm.go | 81 +++++-- core/vm/instructions.go | 357 +++++++++++++++--------------- core/vm/instructions_test.go | 28 +-- core/vm/interpreter.go | 121 +++------- core/vm/jump_table.go | 2 +- eth/tracers/js/tracer_test.go | 2 +- eth/tracers/logger/logger_test.go | 2 +- 8 files changed, 316 insertions(+), 335 deletions(-) diff --git a/core/vm/eips.go b/core/vm/eips.go index 7764bd20b6..10ca1fe9ab 100644 --- a/core/vm/eips.go +++ b/core/vm/eips.go @@ -89,8 +89,8 @@ func enable1884(jt *JumpTable) { } } -func opSelfBalance(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { - balance := interpreter.evm.StateDB.GetBalance(scope.Contract.Address()) +func opSelfBalance(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) { + balance := evm.StateDB.GetBalance(scope.Contract.Address()) scope.Stack.push(balance) return nil, nil } @@ -108,8 +108,8 @@ func enable1344(jt *JumpTable) { } // opChainID implements CHAINID opcode -func opChainID(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { - chainId, _ := uint256.FromBig(interpreter.evm.chainConfig.ChainID) +func opChainID(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) { + chainId, _ := uint256.FromBig(evm.chainConfig.ChainID) scope.Stack.push(chainId) return nil, nil } @@ -199,28 +199,28 @@ func enable1153(jt *JumpTable) { } // opTload implements TLOAD opcode -func opTload(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { +func opTload(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) { loc := scope.Stack.peek() hash := common.Hash(loc.Bytes32()) - val := interpreter.evm.StateDB.GetTransientState(scope.Contract.Address(), hash) + val := evm.StateDB.GetTransientState(scope.Contract.Address(), hash) loc.SetBytes(val.Bytes()) return nil, nil } // opTstore implements TSTORE opcode -func opTstore(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { - if interpreter.readOnly { +func opTstore(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) { + if evm.readOnly { return nil, ErrWriteProtection } loc := scope.Stack.pop() val := scope.Stack.pop() - interpreter.evm.StateDB.SetTransientState(scope.Contract.Address(), loc.Bytes32(), val.Bytes32()) + evm.StateDB.SetTransientState(scope.Contract.Address(), loc.Bytes32(), val.Bytes32()) return nil, nil } // opBaseFee implements BASEFEE opcode -func opBaseFee(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { - baseFee, _ := uint256.FromBig(interpreter.evm.Context.BaseFee) +func opBaseFee(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) { + baseFee, _ := uint256.FromBig(evm.Context.BaseFee) scope.Stack.push(baseFee) return nil, nil } @@ -237,7 +237,7 @@ func enable3855(jt *JumpTable) { } // opPush0 implements the PUSH0 opcode -func opPush0(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { +func opPush0(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) { scope.Stack.push(new(uint256.Int)) return nil, nil } @@ -263,7 +263,7 @@ func enable5656(jt *JumpTable) { } // opMcopy implements the MCOPY opcode (https://eips.ethereum.org/EIPS/eip-5656) -func opMcopy(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { +func opMcopy(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) { var ( dst = scope.Stack.pop() src = scope.Stack.pop() @@ -276,10 +276,10 @@ func opMcopy(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]by } // opBlobHash implements the BLOBHASH opcode -func opBlobHash(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { +func opBlobHash(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) { index := scope.Stack.peek() - if index.LtUint64(uint64(len(interpreter.evm.TxContext.BlobHashes))) { - blobHash := interpreter.evm.TxContext.BlobHashes[index.Uint64()] + if index.LtUint64(uint64(len(evm.TxContext.BlobHashes))) { + blobHash := evm.TxContext.BlobHashes[index.Uint64()] index.SetBytes32(blobHash[:]) } else { index.Clear() @@ -288,14 +288,14 @@ func opBlobHash(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([ } // opBlobBaseFee implements BLOBBASEFEE opcode -func opBlobBaseFee(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { - blobBaseFee, _ := uint256.FromBig(interpreter.evm.Context.BlobBaseFee) +func opBlobBaseFee(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) { + blobBaseFee, _ := uint256.FromBig(evm.Context.BlobBaseFee) scope.Stack.push(blobBaseFee) return nil, nil } // opCLZ implements the CLZ opcode (count leading zero bytes) -func opCLZ(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { +func opCLZ(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) { x := scope.Stack.peek() x.SetUint64(256 - uint64(x.BitLen())) return nil, nil @@ -342,7 +342,7 @@ func enable6780(jt *JumpTable) { } } -func opExtCodeCopyEIP4762(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { +func opExtCodeCopyEIP4762(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) { var ( stack = scope.Stack a = stack.pop() @@ -355,10 +355,10 @@ func opExtCodeCopyEIP4762(pc *uint64, interpreter *EVMInterpreter, scope *ScopeC uint64CodeOffset = math.MaxUint64 } addr := common.Address(a.Bytes20()) - code := interpreter.evm.StateDB.GetCode(addr) + code := evm.StateDB.GetCode(addr) paddedCodeCopy, copyOffset, nonPaddedCopyLength := getDataAndAdjustedBounds(code, uint64CodeOffset, length.Uint64()) - consumed, wanted := interpreter.evm.AccessEvents.CodeChunksRangeGas(addr, copyOffset, nonPaddedCopyLength, uint64(len(code)), false, scope.Contract.Gas) - scope.Contract.UseGas(consumed, interpreter.evm.Config.Tracer, tracing.GasChangeUnspecified) + consumed, wanted := evm.AccessEvents.CodeChunksRangeGas(addr, copyOffset, nonPaddedCopyLength, uint64(len(code)), false, scope.Contract.Gas) + scope.Contract.UseGas(consumed, evm.Config.Tracer, tracing.GasChangeUnspecified) if consumed < wanted { return nil, ErrOutOfGas } @@ -370,7 +370,7 @@ func opExtCodeCopyEIP4762(pc *uint64, interpreter *EVMInterpreter, scope *ScopeC // opPush1EIP4762 handles the special case of PUSH1 opcode for EIP-4762, which // need not worry about the adjusted bound logic when adding the PUSHDATA to // the list of access events. -func opPush1EIP4762(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { +func opPush1EIP4762(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) { var ( codeLen = uint64(len(scope.Contract.Code)) integer = new(uint256.Int) @@ -383,8 +383,8 @@ func opPush1EIP4762(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext // touch next chunk if PUSH1 is at the boundary. if so, *pc has // advanced past this boundary. contractAddr := scope.Contract.Address() - consumed, wanted := interpreter.evm.AccessEvents.CodeChunksRangeGas(contractAddr, *pc+1, uint64(1), uint64(len(scope.Contract.Code)), false, scope.Contract.Gas) - scope.Contract.UseGas(wanted, interpreter.evm.Config.Tracer, tracing.GasChangeUnspecified) + consumed, wanted := evm.AccessEvents.CodeChunksRangeGas(contractAddr, *pc+1, uint64(1), uint64(len(scope.Contract.Code)), false, scope.Contract.Gas) + scope.Contract.UseGas(wanted, evm.Config.Tracer, tracing.GasChangeUnspecified) if consumed < wanted { return nil, ErrOutOfGas } @@ -396,7 +396,7 @@ func opPush1EIP4762(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext } func makePushEIP4762(size uint64, pushByteSize int) executionFunc { - return func(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { + return func(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) { var ( codeLen = len(scope.Contract.Code) start = min(codeLen, int(*pc+1)) @@ -411,8 +411,8 @@ func makePushEIP4762(size uint64, pushByteSize int) executionFunc { if !scope.Contract.IsDeployment && !scope.Contract.IsSystemCall { contractAddr := scope.Contract.Address() - consumed, wanted := interpreter.evm.AccessEvents.CodeChunksRangeGas(contractAddr, uint64(start), uint64(pushByteSize), uint64(len(scope.Contract.Code)), false, scope.Contract.Gas) - scope.Contract.UseGas(consumed, interpreter.evm.Config.Tracer, tracing.GasChangeUnspecified) + consumed, wanted := evm.AccessEvents.CodeChunksRangeGas(contractAddr, uint64(start), uint64(pushByteSize), uint64(len(scope.Contract.Code)), false, scope.Contract.Gas) + scope.Contract.UseGas(consumed, evm.Config.Tracer, tracing.GasChangeUnspecified) if consumed < wanted { return nil, ErrOutOfGas } diff --git a/core/vm/evm.go b/core/vm/evm.go index 143b7e08a2..e360187f7b 100644 --- a/core/vm/evm.go +++ b/core/vm/evm.go @@ -26,6 +26,7 @@ import ( "github.com/ethereum/go-ethereum/core/tracing" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/params" "github.com/holiman/uint256" ) @@ -95,6 +96,9 @@ type EVM struct { // StateDB gives access to the underlying state StateDB StateDB + // table holds the opcode specific handlers + table *JumpTable + // depth is the current call stack depth int @@ -107,10 +111,6 @@ type EVM struct { // virtual machine configuration options used to initialise the evm Config Config - // global (to this context) ethereum virtual machine used throughout - // the execution of the tx - interpreter *EVMInterpreter - // abort is used to abort the EVM calling operations abort atomic.Bool @@ -124,6 +124,12 @@ type EVM struct { // jumpDests stores results of JUMPDEST analysis. jumpDests JumpDestCache + + hasher crypto.KeccakState // Keccak256 hasher instance shared across opcodes + hasherBuf common.Hash // Keccak256 hasher result array shared across opcodes + + readOnly bool // Whether to throw on stateful modifications + returnData []byte // Last CALL's return data for subsequent reuse } // NewEVM constructs an EVM instance with the supplied block context, state @@ -138,9 +144,57 @@ func NewEVM(blockCtx BlockContext, statedb StateDB, chainConfig *params.ChainCon chainConfig: chainConfig, chainRules: chainConfig.Rules(blockCtx.BlockNumber, blockCtx.Random != nil, blockCtx.Time), jumpDests: newMapJumpDests(), + hasher: crypto.NewKeccakState(), } evm.precompiles = activePrecompiledContracts(evm.chainRules) - evm.interpreter = NewEVMInterpreter(evm) + + switch { + case evm.chainRules.IsOsaka: + evm.table = &osakaInstructionSet + case evm.chainRules.IsVerkle: + // TODO replace with proper instruction set when fork is specified + evm.table = &verkleInstructionSet + case evm.chainRules.IsPrague: + evm.table = &pragueInstructionSet + case evm.chainRules.IsCancun: + evm.table = &cancunInstructionSet + case evm.chainRules.IsShanghai: + evm.table = &shanghaiInstructionSet + case evm.chainRules.IsMerge: + evm.table = &mergeInstructionSet + case evm.chainRules.IsLondon: + evm.table = &londonInstructionSet + case evm.chainRules.IsBerlin: + evm.table = &berlinInstructionSet + case evm.chainRules.IsIstanbul: + evm.table = &istanbulInstructionSet + case evm.chainRules.IsConstantinople: + evm.table = &constantinopleInstructionSet + case evm.chainRules.IsByzantium: + evm.table = &byzantiumInstructionSet + case evm.chainRules.IsEIP158: + evm.table = &spuriousDragonInstructionSet + case evm.chainRules.IsEIP150: + evm.table = &tangerineWhistleInstructionSet + case evm.chainRules.IsHomestead: + evm.table = &homesteadInstructionSet + default: + evm.table = &frontierInstructionSet + } + var extraEips []int + if len(evm.Config.ExtraEips) > 0 { + // Deep-copy jumptable to prevent modification of opcodes in other tables + evm.table = copyJumpTable(evm.table) + } + for _, eip := range evm.Config.ExtraEips { + if err := EnableEIP(eip, evm.table); err != nil { + // Disable it, so caller can check if it's activated or not + log.Error("EIP activation failed", "eip", eip, "error", err) + } else { + extraEips = append(extraEips, eip) + } + } + evm.Config.ExtraEips = extraEips return evm } @@ -176,11 +230,6 @@ func (evm *EVM) Cancelled() bool { return evm.abort.Load() } -// Interpreter returns the current interpreter -func (evm *EVM) Interpreter() *EVMInterpreter { - return evm.interpreter -} - func isSystemCall(caller common.Address) bool { return caller == params.SystemAddress } @@ -245,7 +294,7 @@ func (evm *EVM) Call(caller common.Address, addr common.Address, input []byte, g contract := NewContract(caller, addr, value, gas, evm.jumpDests) contract.IsSystemCall = isSystemCall(caller) contract.SetCallCode(evm.resolveCodeHash(addr), code) - ret, err = evm.interpreter.Run(contract, input, false) + ret, err = evm.Run(contract, input, false) gas = contract.Gas } } @@ -304,7 +353,7 @@ func (evm *EVM) CallCode(caller common.Address, addr common.Address, input []byt // The contract is a scoped environment for this execution context only. contract := NewContract(caller, caller, value, gas, evm.jumpDests) contract.SetCallCode(evm.resolveCodeHash(addr), evm.resolveCode(addr)) - ret, err = evm.interpreter.Run(contract, input, false) + ret, err = evm.Run(contract, input, false) gas = contract.Gas } if err != nil { @@ -348,7 +397,7 @@ func (evm *EVM) DelegateCall(originCaller common.Address, caller common.Address, // Note: The value refers to the original value from the parent call. contract := NewContract(originCaller, caller, value, gas, evm.jumpDests) contract.SetCallCode(evm.resolveCodeHash(addr), evm.resolveCode(addr)) - ret, err = evm.interpreter.Run(contract, input, false) + ret, err = evm.Run(contract, input, false) gas = contract.Gas } if err != nil { @@ -403,7 +452,7 @@ func (evm *EVM) StaticCall(caller common.Address, addr common.Address, input []b // When an error was returned by the EVM or when setting the creation code // above we revert to the snapshot and consume any gas remaining. Additionally // when we're in Homestead this also counts for code storage gas errors. - ret, err = evm.interpreter.Run(contract, input, true) + ret, err = evm.Run(contract, input, true) gas = contract.Gas } if err != nil { @@ -524,7 +573,7 @@ func (evm *EVM) create(caller common.Address, code []byte, gas uint64, value *ui // initNewContract runs a new contract's creation code, performs checks on the // resulting code that is to be deployed, and consumes necessary gas. func (evm *EVM) initNewContract(contract *Contract, address common.Address) ([]byte, error) { - ret, err := evm.interpreter.Run(contract, nil, false) + ret, err := evm.Run(contract, nil, false) if err != nil { return ret, err } @@ -567,7 +616,7 @@ func (evm *EVM) Create(caller common.Address, code []byte, gas uint64, value *ui // The different between Create2 with Create is Create2 uses keccak256(0xff ++ msg.sender ++ salt ++ keccak256(init_code))[12:] // instead of the usual sender-and-nonce-hash as the address where the contract is initialized at. func (evm *EVM) Create2(caller common.Address, code []byte, gas uint64, endowment *uint256.Int, salt *uint256.Int) (ret []byte, contractAddr common.Address, leftOverGas uint64, err error) { - inithash := crypto.HashData(evm.interpreter.hasher, code) + inithash := crypto.HashData(evm.hasher, code) contractAddr = crypto.CreateAddress2(caller, salt.Bytes32(), inithash[:]) return evm.create(caller, code, gas, endowment, contractAddr, CREATE2) } diff --git a/core/vm/instructions.go b/core/vm/instructions.go index 63bb6d2d51..fffa65fd6a 100644 --- a/core/vm/instructions.go +++ b/core/vm/instructions.go @@ -26,67 +26,67 @@ import ( "github.com/holiman/uint256" ) -func opAdd(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { +func opAdd(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) { x, y := scope.Stack.pop(), scope.Stack.peek() y.Add(&x, y) return nil, nil } -func opSub(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { +func opSub(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) { x, y := scope.Stack.pop(), scope.Stack.peek() y.Sub(&x, y) return nil, nil } -func opMul(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { +func opMul(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) { x, y := scope.Stack.pop(), scope.Stack.peek() y.Mul(&x, y) return nil, nil } -func opDiv(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { +func opDiv(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) { x, y := scope.Stack.pop(), scope.Stack.peek() y.Div(&x, y) return nil, nil } -func opSdiv(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { +func opSdiv(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) { x, y := scope.Stack.pop(), scope.Stack.peek() y.SDiv(&x, y) return nil, nil } -func opMod(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { +func opMod(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) { x, y := scope.Stack.pop(), scope.Stack.peek() y.Mod(&x, y) return nil, nil } -func opSmod(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { +func opSmod(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) { x, y := scope.Stack.pop(), scope.Stack.peek() y.SMod(&x, y) return nil, nil } -func opExp(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { +func opExp(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) { base, exponent := scope.Stack.pop(), scope.Stack.peek() exponent.Exp(&base, exponent) return nil, nil } -func opSignExtend(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { +func opSignExtend(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) { back, num := scope.Stack.pop(), scope.Stack.peek() num.ExtendSign(num, &back) return nil, nil } -func opNot(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { +func opNot(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) { x := scope.Stack.peek() x.Not(x) return nil, nil } -func opLt(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { +func opLt(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) { x, y := scope.Stack.pop(), scope.Stack.peek() if x.Lt(y) { y.SetOne() @@ -96,7 +96,7 @@ func opLt(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, return nil, nil } -func opGt(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { +func opGt(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) { x, y := scope.Stack.pop(), scope.Stack.peek() if x.Gt(y) { y.SetOne() @@ -106,7 +106,7 @@ func opGt(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, return nil, nil } -func opSlt(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { +func opSlt(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) { x, y := scope.Stack.pop(), scope.Stack.peek() if x.Slt(y) { y.SetOne() @@ -116,7 +116,7 @@ func opSlt(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte return nil, nil } -func opSgt(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { +func opSgt(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) { x, y := scope.Stack.pop(), scope.Stack.peek() if x.Sgt(y) { y.SetOne() @@ -126,7 +126,7 @@ func opSgt(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte return nil, nil } -func opEq(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { +func opEq(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) { x, y := scope.Stack.pop(), scope.Stack.peek() if x.Eq(y) { y.SetOne() @@ -136,7 +136,7 @@ func opEq(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, return nil, nil } -func opIszero(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { +func opIszero(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) { x := scope.Stack.peek() if x.IsZero() { x.SetOne() @@ -146,37 +146,37 @@ func opIszero(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]b return nil, nil } -func opAnd(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { +func opAnd(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) { x, y := scope.Stack.pop(), scope.Stack.peek() y.And(&x, y) return nil, nil } -func opOr(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { +func opOr(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) { x, y := scope.Stack.pop(), scope.Stack.peek() y.Or(&x, y) return nil, nil } -func opXor(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { +func opXor(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) { x, y := scope.Stack.pop(), scope.Stack.peek() y.Xor(&x, y) return nil, nil } -func opByte(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { +func opByte(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) { th, val := scope.Stack.pop(), scope.Stack.peek() val.Byte(&th) return nil, nil } -func opAddmod(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { +func opAddmod(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) { x, y, z := scope.Stack.pop(), scope.Stack.pop(), scope.Stack.peek() z.AddMod(&x, &y, z) return nil, nil } -func opMulmod(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { +func opMulmod(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) { x, y, z := scope.Stack.pop(), scope.Stack.pop(), scope.Stack.peek() z.MulMod(&x, &y, z) return nil, nil @@ -185,7 +185,7 @@ func opMulmod(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]b // opSHL implements Shift Left // The SHL instruction (shift left) pops 2 values from the stack, first arg1 and then arg2, // and pushes on the stack arg2 shifted to the left by arg1 number of bits. -func opSHL(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { +func opSHL(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) { // Note, second operand is left in the stack; accumulate result into it, and no need to push it afterwards shift, value := scope.Stack.pop(), scope.Stack.peek() if shift.LtUint64(256) { @@ -199,7 +199,7 @@ func opSHL(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte // opSHR implements Logical Shift Right // The SHR instruction (logical shift right) pops 2 values from the stack, first arg1 and then arg2, // and pushes on the stack arg2 shifted to the right by arg1 number of bits with zero fill. -func opSHR(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { +func opSHR(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) { // Note, second operand is left in the stack; accumulate result into it, and no need to push it afterwards shift, value := scope.Stack.pop(), scope.Stack.peek() if shift.LtUint64(256) { @@ -213,7 +213,7 @@ func opSHR(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte // opSAR implements Arithmetic Shift Right // The SAR instruction (arithmetic shift right) pops 2 values from the stack, first arg1 and then arg2, // and pushes on the stack arg2 shifted to the right by arg1 number of bits with sign extension. -func opSAR(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { +func opSAR(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) { shift, value := scope.Stack.pop(), scope.Stack.peek() if shift.GtUint64(256) { if value.Sign() >= 0 { @@ -229,50 +229,49 @@ func opSAR(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte return nil, nil } -func opKeccak256(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { +func opKeccak256(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) { offset, size := scope.Stack.pop(), scope.Stack.peek() data := scope.Memory.GetPtr(offset.Uint64(), size.Uint64()) - interpreter.hasher.Reset() - interpreter.hasher.Write(data) - interpreter.hasher.Read(interpreter.hasherBuf[:]) + evm.hasher.Reset() + evm.hasher.Write(data) + evm.hasher.Read(evm.hasherBuf[:]) - evm := interpreter.evm if evm.Config.EnablePreimageRecording { - evm.StateDB.AddPreimage(interpreter.hasherBuf, data) + evm.StateDB.AddPreimage(evm.hasherBuf, data) } - size.SetBytes(interpreter.hasherBuf[:]) + size.SetBytes(evm.hasherBuf[:]) return nil, nil } -func opAddress(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { +func opAddress(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) { scope.Stack.push(new(uint256.Int).SetBytes(scope.Contract.Address().Bytes())) return nil, nil } -func opBalance(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { +func opBalance(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) { slot := scope.Stack.peek() address := common.Address(slot.Bytes20()) - slot.Set(interpreter.evm.StateDB.GetBalance(address)) + slot.Set(evm.StateDB.GetBalance(address)) return nil, nil } -func opOrigin(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { - scope.Stack.push(new(uint256.Int).SetBytes(interpreter.evm.Origin.Bytes())) +func opOrigin(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) { + scope.Stack.push(new(uint256.Int).SetBytes(evm.Origin.Bytes())) return nil, nil } -func opCaller(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { +func opCaller(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) { scope.Stack.push(new(uint256.Int).SetBytes(scope.Contract.Caller().Bytes())) return nil, nil } -func opCallValue(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { +func opCallValue(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) { scope.Stack.push(scope.Contract.value) return nil, nil } -func opCallDataLoad(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { +func opCallDataLoad(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) { x := scope.Stack.peek() if offset, overflow := x.Uint64WithOverflow(); !overflow { data := getData(scope.Contract.Input, offset, 32) @@ -283,12 +282,12 @@ func opCallDataLoad(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext return nil, nil } -func opCallDataSize(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { +func opCallDataSize(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) { scope.Stack.push(new(uint256.Int).SetUint64(uint64(len(scope.Contract.Input)))) return nil, nil } -func opCallDataCopy(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { +func opCallDataCopy(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) { var ( memOffset = scope.Stack.pop() dataOffset = scope.Stack.pop() @@ -306,12 +305,12 @@ func opCallDataCopy(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext return nil, nil } -func opReturnDataSize(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { - scope.Stack.push(new(uint256.Int).SetUint64(uint64(len(interpreter.returnData)))) +func opReturnDataSize(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) { + scope.Stack.push(new(uint256.Int).SetUint64(uint64(len(evm.returnData)))) return nil, nil } -func opReturnDataCopy(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { +func opReturnDataCopy(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) { var ( memOffset = scope.Stack.pop() dataOffset = scope.Stack.pop() @@ -326,25 +325,25 @@ func opReturnDataCopy(pc *uint64, interpreter *EVMInterpreter, scope *ScopeConte var end = dataOffset end.Add(&dataOffset, &length) end64, overflow := end.Uint64WithOverflow() - if overflow || uint64(len(interpreter.returnData)) < end64 { + if overflow || uint64(len(evm.returnData)) < end64 { return nil, ErrReturnDataOutOfBounds } - scope.Memory.Set(memOffset.Uint64(), length.Uint64(), interpreter.returnData[offset64:end64]) + scope.Memory.Set(memOffset.Uint64(), length.Uint64(), evm.returnData[offset64:end64]) return nil, nil } -func opExtCodeSize(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { +func opExtCodeSize(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) { slot := scope.Stack.peek() - slot.SetUint64(uint64(interpreter.evm.StateDB.GetCodeSize(slot.Bytes20()))) + slot.SetUint64(uint64(evm.StateDB.GetCodeSize(slot.Bytes20()))) return nil, nil } -func opCodeSize(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { +func opCodeSize(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) { scope.Stack.push(new(uint256.Int).SetUint64(uint64(len(scope.Contract.Code)))) return nil, nil } -func opCodeCopy(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { +func opCodeCopy(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) { var ( memOffset = scope.Stack.pop() codeOffset = scope.Stack.pop() @@ -360,7 +359,7 @@ func opCodeCopy(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([ return nil, nil } -func opExtCodeCopy(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { +func opExtCodeCopy(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) { var ( stack = scope.Stack a = stack.pop() @@ -373,7 +372,7 @@ func opExtCodeCopy(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) uint64CodeOffset = math.MaxUint64 } addr := common.Address(a.Bytes20()) - code := interpreter.evm.StateDB.GetCode(addr) + code := evm.StateDB.GetCode(addr) codeCopy := getData(code, uint64CodeOffset, length.Uint64()) scope.Memory.Set(memOffset.Uint64(), length.Uint64(), codeCopy) @@ -406,24 +405,24 @@ func opExtCodeCopy(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) // // 6. Caller tries to get the code hash for an account which is marked as deleted, this // account should be regarded as a non-existent account and zero should be returned. -func opExtCodeHash(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { +func opExtCodeHash(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) { slot := scope.Stack.peek() address := common.Address(slot.Bytes20()) - if interpreter.evm.StateDB.Empty(address) { + if evm.StateDB.Empty(address) { slot.Clear() } else { - slot.SetBytes(interpreter.evm.StateDB.GetCodeHash(address).Bytes()) + slot.SetBytes(evm.StateDB.GetCodeHash(address).Bytes()) } return nil, nil } -func opGasprice(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { - v, _ := uint256.FromBig(interpreter.evm.GasPrice) +func opGasprice(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) { + v, _ := uint256.FromBig(evm.GasPrice) scope.Stack.push(v) return nil, nil } -func opBlockhash(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { +func opBlockhash(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) { num := scope.Stack.peek() num64, overflow := num.Uint64WithOverflow() if overflow { @@ -432,18 +431,18 @@ func opBlockhash(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ( } var upper, lower uint64 - upper = interpreter.evm.Context.BlockNumber.Uint64() + upper = evm.Context.BlockNumber.Uint64() if upper < 257 { lower = 0 } else { lower = upper - 256 } if num64 >= lower && num64 < upper { - res := interpreter.evm.Context.GetHash(num64) - if witness := interpreter.evm.StateDB.Witness(); witness != nil { + res := evm.Context.GetHash(num64) + if witness := evm.StateDB.Witness(); witness != nil { witness.AddBlockHash(num64) } - if tracer := interpreter.evm.Config.Tracer; tracer != nil && tracer.OnBlockHashRead != nil { + if tracer := evm.Config.Tracer; tracer != nil && tracer.OnBlockHashRead != nil { tracer.OnBlockHashRead(num64, res) } num.SetBytes(res[:]) @@ -453,83 +452,83 @@ func opBlockhash(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ( return nil, nil } -func opCoinbase(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { - scope.Stack.push(new(uint256.Int).SetBytes(interpreter.evm.Context.Coinbase.Bytes())) +func opCoinbase(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) { + scope.Stack.push(new(uint256.Int).SetBytes(evm.Context.Coinbase.Bytes())) return nil, nil } -func opTimestamp(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { - scope.Stack.push(new(uint256.Int).SetUint64(interpreter.evm.Context.Time)) +func opTimestamp(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) { + scope.Stack.push(new(uint256.Int).SetUint64(evm.Context.Time)) return nil, nil } -func opNumber(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { - v, _ := uint256.FromBig(interpreter.evm.Context.BlockNumber) +func opNumber(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) { + v, _ := uint256.FromBig(evm.Context.BlockNumber) scope.Stack.push(v) return nil, nil } -func opDifficulty(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { - v, _ := uint256.FromBig(interpreter.evm.Context.Difficulty) +func opDifficulty(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) { + v, _ := uint256.FromBig(evm.Context.Difficulty) scope.Stack.push(v) return nil, nil } -func opRandom(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { - v := new(uint256.Int).SetBytes(interpreter.evm.Context.Random.Bytes()) +func opRandom(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) { + v := new(uint256.Int).SetBytes(evm.Context.Random.Bytes()) scope.Stack.push(v) return nil, nil } -func opGasLimit(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { - scope.Stack.push(new(uint256.Int).SetUint64(interpreter.evm.Context.GasLimit)) +func opGasLimit(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) { + scope.Stack.push(new(uint256.Int).SetUint64(evm.Context.GasLimit)) return nil, nil } -func opPop(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { +func opPop(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) { scope.Stack.pop() return nil, nil } -func opMload(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { +func opMload(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) { v := scope.Stack.peek() offset := v.Uint64() v.SetBytes(scope.Memory.GetPtr(offset, 32)) return nil, nil } -func opMstore(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { +func opMstore(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) { mStart, val := scope.Stack.pop(), scope.Stack.pop() scope.Memory.Set32(mStart.Uint64(), &val) return nil, nil } -func opMstore8(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { +func opMstore8(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) { off, val := scope.Stack.pop(), scope.Stack.pop() scope.Memory.store[off.Uint64()] = byte(val.Uint64()) return nil, nil } -func opSload(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { +func opSload(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) { loc := scope.Stack.peek() hash := common.Hash(loc.Bytes32()) - val := interpreter.evm.StateDB.GetState(scope.Contract.Address(), hash) + val := evm.StateDB.GetState(scope.Contract.Address(), hash) loc.SetBytes(val.Bytes()) return nil, nil } -func opSstore(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { - if interpreter.readOnly { +func opSstore(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) { + if evm.readOnly { return nil, ErrWriteProtection } loc := scope.Stack.pop() val := scope.Stack.pop() - interpreter.evm.StateDB.SetState(scope.Contract.Address(), loc.Bytes32(), val.Bytes32()) + evm.StateDB.SetState(scope.Contract.Address(), loc.Bytes32(), val.Bytes32()) return nil, nil } -func opJump(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { - if interpreter.evm.abort.Load() { +func opJump(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) { + if evm.abort.Load() { return nil, errStopToken } pos := scope.Stack.pop() @@ -540,8 +539,8 @@ func opJump(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byt return nil, nil } -func opJumpi(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { - if interpreter.evm.abort.Load() { +func opJumpi(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) { + if evm.abort.Load() { return nil, errStopToken } pos, cond := scope.Stack.pop(), scope.Stack.pop() @@ -554,107 +553,107 @@ func opJumpi(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]by return nil, nil } -func opJumpdest(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { +func opJumpdest(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) { return nil, nil } -func opPc(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { +func opPc(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) { scope.Stack.push(new(uint256.Int).SetUint64(*pc)) return nil, nil } -func opMsize(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { +func opMsize(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) { scope.Stack.push(new(uint256.Int).SetUint64(uint64(scope.Memory.Len()))) return nil, nil } -func opGas(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { +func opGas(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) { scope.Stack.push(new(uint256.Int).SetUint64(scope.Contract.Gas)) return nil, nil } -func opSwap1(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { +func opSwap1(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) { scope.Stack.swap1() return nil, nil } -func opSwap2(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { +func opSwap2(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) { scope.Stack.swap2() return nil, nil } -func opSwap3(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { +func opSwap3(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) { scope.Stack.swap3() return nil, nil } -func opSwap4(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { +func opSwap4(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) { scope.Stack.swap4() return nil, nil } -func opSwap5(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { +func opSwap5(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) { scope.Stack.swap5() return nil, nil } -func opSwap6(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { +func opSwap6(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) { scope.Stack.swap6() return nil, nil } -func opSwap7(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { +func opSwap7(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) { scope.Stack.swap7() return nil, nil } -func opSwap8(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { +func opSwap8(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) { scope.Stack.swap8() return nil, nil } -func opSwap9(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { +func opSwap9(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) { scope.Stack.swap9() return nil, nil } -func opSwap10(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { +func opSwap10(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) { scope.Stack.swap10() return nil, nil } -func opSwap11(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { +func opSwap11(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) { scope.Stack.swap11() return nil, nil } -func opSwap12(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { +func opSwap12(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) { scope.Stack.swap12() return nil, nil } -func opSwap13(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { +func opSwap13(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) { scope.Stack.swap13() return nil, nil } -func opSwap14(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { +func opSwap14(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) { scope.Stack.swap14() return nil, nil } -func opSwap15(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { +func opSwap15(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) { scope.Stack.swap15() return nil, nil } -func opSwap16(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { +func opSwap16(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) { scope.Stack.swap16() return nil, nil } -func opCreate(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { - if interpreter.readOnly { +func opCreate(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) { + if evm.readOnly { return nil, ErrWriteProtection } var ( @@ -663,21 +662,21 @@ func opCreate(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]b input = scope.Memory.GetCopy(offset.Uint64(), size.Uint64()) gas = scope.Contract.Gas ) - if interpreter.evm.chainRules.IsEIP150 { + if evm.chainRules.IsEIP150 { gas -= gas / 64 } // reuse size int for stackvalue stackvalue := size - scope.Contract.UseGas(gas, interpreter.evm.Config.Tracer, tracing.GasChangeCallContractCreation) + scope.Contract.UseGas(gas, evm.Config.Tracer, tracing.GasChangeCallContractCreation) - res, addr, returnGas, suberr := interpreter.evm.Create(scope.Contract.Address(), input, gas, &value) + res, addr, returnGas, suberr := evm.Create(scope.Contract.Address(), input, gas, &value) // Push item on the stack based on the returned error. If the ruleset is // homestead we must check for CodeStoreOutOfGasError (homestead only // rule) and treat as an error, if the ruleset is frontier we must // ignore this error and pretend the operation was successful. - if interpreter.evm.chainRules.IsHomestead && suberr == ErrCodeStoreOutOfGas { + if evm.chainRules.IsHomestead && suberr == ErrCodeStoreOutOfGas { stackvalue.Clear() } else if suberr != nil && suberr != ErrCodeStoreOutOfGas { stackvalue.Clear() @@ -686,18 +685,18 @@ func opCreate(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]b } scope.Stack.push(&stackvalue) - scope.Contract.RefundGas(returnGas, interpreter.evm.Config.Tracer, tracing.GasChangeCallLeftOverRefunded) + scope.Contract.RefundGas(returnGas, evm.Config.Tracer, tracing.GasChangeCallLeftOverRefunded) if suberr == ErrExecutionReverted { - interpreter.returnData = res // set REVERT data to return data buffer + evm.returnData = res // set REVERT data to return data buffer return res, nil } - interpreter.returnData = nil // clear dirty return data buffer + evm.returnData = nil // clear dirty return data buffer return nil, nil } -func opCreate2(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { - if interpreter.readOnly { +func opCreate2(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) { + if evm.readOnly { return nil, ErrWriteProtection } var ( @@ -710,10 +709,10 @@ func opCreate2(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([] // Apply EIP150 gas -= gas / 64 - scope.Contract.UseGas(gas, interpreter.evm.Config.Tracer, tracing.GasChangeCallContractCreation2) + scope.Contract.UseGas(gas, evm.Config.Tracer, tracing.GasChangeCallContractCreation2) // reuse size int for stackvalue stackvalue := size - res, addr, returnGas, suberr := interpreter.evm.Create2(scope.Contract.Address(), input, gas, + res, addr, returnGas, suberr := evm.Create2(scope.Contract.Address(), input, gas, &endowment, &salt) // Push item on the stack based on the returned error. if suberr != nil { @@ -722,35 +721,35 @@ func opCreate2(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([] stackvalue.SetBytes(addr.Bytes()) } scope.Stack.push(&stackvalue) - scope.Contract.RefundGas(returnGas, interpreter.evm.Config.Tracer, tracing.GasChangeCallLeftOverRefunded) + scope.Contract.RefundGas(returnGas, evm.Config.Tracer, tracing.GasChangeCallLeftOverRefunded) if suberr == ErrExecutionReverted { - interpreter.returnData = res // set REVERT data to return data buffer + evm.returnData = res // set REVERT data to return data buffer return res, nil } - interpreter.returnData = nil // clear dirty return data buffer + evm.returnData = nil // clear dirty return data buffer return nil, nil } -func opCall(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { +func opCall(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) { stack := scope.Stack - // Pop gas. The actual gas in interpreter.evm.callGasTemp. + // Pop gas. The actual gas in evm.callGasTemp. // We can use this as a temporary value temp := stack.pop() - gas := interpreter.evm.callGasTemp + gas := evm.callGasTemp // Pop other call parameters. addr, value, inOffset, inSize, retOffset, retSize := stack.pop(), stack.pop(), stack.pop(), stack.pop(), stack.pop(), stack.pop() toAddr := common.Address(addr.Bytes20()) // Get the arguments from the memory. args := scope.Memory.GetPtr(inOffset.Uint64(), inSize.Uint64()) - if interpreter.readOnly && !value.IsZero() { + if evm.readOnly && !value.IsZero() { return nil, ErrWriteProtection } if !value.IsZero() { gas += params.CallStipend } - ret, returnGas, err := interpreter.evm.Call(scope.Contract.Address(), toAddr, args, gas, &value) + ret, returnGas, err := evm.Call(scope.Contract.Address(), toAddr, args, gas, &value) if err != nil { temp.Clear() @@ -762,18 +761,18 @@ func opCall(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byt scope.Memory.Set(retOffset.Uint64(), retSize.Uint64(), ret) } - scope.Contract.RefundGas(returnGas, interpreter.evm.Config.Tracer, tracing.GasChangeCallLeftOverRefunded) + scope.Contract.RefundGas(returnGas, evm.Config.Tracer, tracing.GasChangeCallLeftOverRefunded) - interpreter.returnData = ret + evm.returnData = ret return ret, nil } -func opCallCode(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { - // Pop gas. The actual gas is in interpreter.evm.callGasTemp. +func opCallCode(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) { + // Pop gas. The actual gas is in evm.callGasTemp. stack := scope.Stack // We use it as a temporary value temp := stack.pop() - gas := interpreter.evm.callGasTemp + gas := evm.callGasTemp // Pop other call parameters. addr, value, inOffset, inSize, retOffset, retSize := stack.pop(), stack.pop(), stack.pop(), stack.pop(), stack.pop(), stack.pop() toAddr := common.Address(addr.Bytes20()) @@ -784,7 +783,7 @@ func opCallCode(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([ gas += params.CallStipend } - ret, returnGas, err := interpreter.evm.CallCode(scope.Contract.Address(), toAddr, args, gas, &value) + ret, returnGas, err := evm.CallCode(scope.Contract.Address(), toAddr, args, gas, &value) if err != nil { temp.Clear() } else { @@ -795,25 +794,25 @@ func opCallCode(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([ scope.Memory.Set(retOffset.Uint64(), retSize.Uint64(), ret) } - scope.Contract.RefundGas(returnGas, interpreter.evm.Config.Tracer, tracing.GasChangeCallLeftOverRefunded) + scope.Contract.RefundGas(returnGas, evm.Config.Tracer, tracing.GasChangeCallLeftOverRefunded) - interpreter.returnData = ret + evm.returnData = ret return ret, nil } -func opDelegateCall(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { +func opDelegateCall(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) { stack := scope.Stack - // Pop gas. The actual gas is in interpreter.evm.callGasTemp. + // Pop gas. The actual gas is in evm.callGasTemp. // We use it as a temporary value temp := stack.pop() - gas := interpreter.evm.callGasTemp + gas := evm.callGasTemp // Pop other call parameters. addr, inOffset, inSize, retOffset, retSize := stack.pop(), stack.pop(), stack.pop(), stack.pop(), stack.pop() toAddr := common.Address(addr.Bytes20()) // Get arguments from the memory. args := scope.Memory.GetPtr(inOffset.Uint64(), inSize.Uint64()) - ret, returnGas, err := interpreter.evm.DelegateCall(scope.Contract.Caller(), scope.Contract.Address(), toAddr, args, gas, scope.Contract.value) + ret, returnGas, err := evm.DelegateCall(scope.Contract.Caller(), scope.Contract.Address(), toAddr, args, gas, scope.Contract.value) if err != nil { temp.Clear() } else { @@ -824,25 +823,25 @@ func opDelegateCall(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext scope.Memory.Set(retOffset.Uint64(), retSize.Uint64(), ret) } - scope.Contract.RefundGas(returnGas, interpreter.evm.Config.Tracer, tracing.GasChangeCallLeftOverRefunded) + scope.Contract.RefundGas(returnGas, evm.Config.Tracer, tracing.GasChangeCallLeftOverRefunded) - interpreter.returnData = ret + evm.returnData = ret return ret, nil } -func opStaticCall(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { - // Pop gas. The actual gas is in interpreter.evm.callGasTemp. +func opStaticCall(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) { + // Pop gas. The actual gas is in evm.callGasTemp. stack := scope.Stack // We use it as a temporary value temp := stack.pop() - gas := interpreter.evm.callGasTemp + gas := evm.callGasTemp // Pop other call parameters. addr, inOffset, inSize, retOffset, retSize := stack.pop(), stack.pop(), stack.pop(), stack.pop(), stack.pop() toAddr := common.Address(addr.Bytes20()) // Get arguments from the memory. args := scope.Memory.GetPtr(inOffset.Uint64(), inSize.Uint64()) - ret, returnGas, err := interpreter.evm.StaticCall(scope.Contract.Address(), toAddr, args, gas) + ret, returnGas, err := evm.StaticCall(scope.Contract.Address(), toAddr, args, gas) if err != nil { temp.Clear() } else { @@ -853,69 +852,69 @@ func opStaticCall(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) scope.Memory.Set(retOffset.Uint64(), retSize.Uint64(), ret) } - scope.Contract.RefundGas(returnGas, interpreter.evm.Config.Tracer, tracing.GasChangeCallLeftOverRefunded) + scope.Contract.RefundGas(returnGas, evm.Config.Tracer, tracing.GasChangeCallLeftOverRefunded) - interpreter.returnData = ret + evm.returnData = ret return ret, nil } -func opReturn(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { +func opReturn(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) { offset, size := scope.Stack.pop(), scope.Stack.pop() ret := scope.Memory.GetCopy(offset.Uint64(), size.Uint64()) return ret, errStopToken } -func opRevert(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { +func opRevert(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) { offset, size := scope.Stack.pop(), scope.Stack.pop() ret := scope.Memory.GetCopy(offset.Uint64(), size.Uint64()) - interpreter.returnData = ret + evm.returnData = ret return ret, ErrExecutionReverted } -func opUndefined(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { +func opUndefined(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) { return nil, &ErrInvalidOpCode{opcode: OpCode(scope.Contract.Code[*pc])} } -func opStop(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { +func opStop(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) { return nil, errStopToken } -func opSelfdestruct(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { - if interpreter.readOnly { +func opSelfdestruct(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) { + if evm.readOnly { return nil, ErrWriteProtection } beneficiary := scope.Stack.pop() - balance := interpreter.evm.StateDB.GetBalance(scope.Contract.Address()) - interpreter.evm.StateDB.AddBalance(beneficiary.Bytes20(), balance, tracing.BalanceIncreaseSelfdestruct) - interpreter.evm.StateDB.SelfDestruct(scope.Contract.Address()) - if tracer := interpreter.evm.Config.Tracer; tracer != nil { + balance := evm.StateDB.GetBalance(scope.Contract.Address()) + evm.StateDB.AddBalance(beneficiary.Bytes20(), balance, tracing.BalanceIncreaseSelfdestruct) + evm.StateDB.SelfDestruct(scope.Contract.Address()) + if tracer := evm.Config.Tracer; tracer != nil { if tracer.OnEnter != nil { - tracer.OnEnter(interpreter.evm.depth, byte(SELFDESTRUCT), scope.Contract.Address(), beneficiary.Bytes20(), []byte{}, 0, balance.ToBig()) + tracer.OnEnter(evm.depth, byte(SELFDESTRUCT), scope.Contract.Address(), beneficiary.Bytes20(), []byte{}, 0, balance.ToBig()) } if tracer.OnExit != nil { - tracer.OnExit(interpreter.evm.depth, []byte{}, 0, nil, false) + tracer.OnExit(evm.depth, []byte{}, 0, nil, false) } } return nil, errStopToken } -func opSelfdestruct6780(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { - if interpreter.readOnly { +func opSelfdestruct6780(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) { + if evm.readOnly { return nil, ErrWriteProtection } beneficiary := scope.Stack.pop() - balance := interpreter.evm.StateDB.GetBalance(scope.Contract.Address()) - interpreter.evm.StateDB.SubBalance(scope.Contract.Address(), balance, tracing.BalanceDecreaseSelfdestruct) - interpreter.evm.StateDB.AddBalance(beneficiary.Bytes20(), balance, tracing.BalanceIncreaseSelfdestruct) - interpreter.evm.StateDB.SelfDestruct6780(scope.Contract.Address()) - if tracer := interpreter.evm.Config.Tracer; tracer != nil { + balance := evm.StateDB.GetBalance(scope.Contract.Address()) + evm.StateDB.SubBalance(scope.Contract.Address(), balance, tracing.BalanceDecreaseSelfdestruct) + evm.StateDB.AddBalance(beneficiary.Bytes20(), balance, tracing.BalanceIncreaseSelfdestruct) + evm.StateDB.SelfDestruct6780(scope.Contract.Address()) + if tracer := evm.Config.Tracer; tracer != nil { if tracer.OnEnter != nil { - tracer.OnEnter(interpreter.evm.depth, byte(SELFDESTRUCT), scope.Contract.Address(), beneficiary.Bytes20(), []byte{}, 0, balance.ToBig()) + tracer.OnEnter(evm.depth, byte(SELFDESTRUCT), scope.Contract.Address(), beneficiary.Bytes20(), []byte{}, 0, balance.ToBig()) } if tracer.OnExit != nil { - tracer.OnExit(interpreter.evm.depth, []byte{}, 0, nil, false) + tracer.OnExit(evm.depth, []byte{}, 0, nil, false) } } return nil, errStopToken @@ -925,8 +924,8 @@ func opSelfdestruct6780(pc *uint64, interpreter *EVMInterpreter, scope *ScopeCon // make log instruction function func makeLog(size int) executionFunc { - return func(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { - if interpreter.readOnly { + return func(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) { + if evm.readOnly { return nil, ErrWriteProtection } topics := make([]common.Hash, size) @@ -938,13 +937,13 @@ func makeLog(size int) executionFunc { } d := scope.Memory.GetCopy(mStart.Uint64(), mSize.Uint64()) - interpreter.evm.StateDB.AddLog(&types.Log{ + evm.StateDB.AddLog(&types.Log{ Address: scope.Contract.Address(), Topics: topics, Data: d, // This is a non-consensus field, but assigned here because // core/state doesn't know the current block number. - BlockNumber: interpreter.evm.Context.BlockNumber.Uint64(), + BlockNumber: evm.Context.BlockNumber.Uint64(), }) return nil, nil @@ -952,7 +951,7 @@ func makeLog(size int) executionFunc { } // opPush1 is a specialized version of pushN -func opPush1(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { +func opPush1(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) { var ( codeLen = uint64(len(scope.Contract.Code)) integer = new(uint256.Int) @@ -967,7 +966,7 @@ func opPush1(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]by } // opPush2 is a specialized version of pushN -func opPush2(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { +func opPush2(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) { var ( codeLen = uint64(len(scope.Contract.Code)) integer = new(uint256.Int) @@ -985,7 +984,7 @@ func opPush2(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]by // make push instruction function func makePush(size uint64, pushByteSize int) executionFunc { - return func(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { + return func(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) { var ( codeLen = len(scope.Contract.Code) start = min(codeLen, int(*pc+1)) @@ -1005,7 +1004,7 @@ func makePush(size uint64, pushByteSize int) executionFunc { // make dup instruction function func makeDup(size int64) executionFunc { - return func(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { + return func(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) { scope.Stack.dup(int(size)) return nil, nil } diff --git a/core/vm/instructions_test.go b/core/vm/instructions_test.go index 8a82de5d8b..cd31829a7e 100644 --- a/core/vm/instructions_test.go +++ b/core/vm/instructions_test.go @@ -107,7 +107,7 @@ func testTwoOperandOp(t *testing.T, tests []TwoOperandTestcase, opFn executionFu expected := new(uint256.Int).SetBytes(common.Hex2Bytes(test.Expected)) stack.push(x) stack.push(y) - opFn(&pc, evm.interpreter, &ScopeContext{nil, stack, nil}) + opFn(&pc, evm, &ScopeContext{nil, stack, nil}) if len(stack.data) != 1 { t.Errorf("Expected one item on stack after %v, got %d: ", name, len(stack.data)) } @@ -221,7 +221,7 @@ func TestAddMod(t *testing.T) { stack.push(z) stack.push(y) stack.push(x) - opAddmod(&pc, evm.interpreter, &ScopeContext{nil, stack, nil}) + opAddmod(&pc, evm, &ScopeContext{nil, stack, nil}) actual := stack.pop() if actual.Cmp(expected) != 0 { t.Errorf("Testcase %d, expected %x, got %x", i, expected, actual) @@ -247,7 +247,7 @@ func TestWriteExpectedValues(t *testing.T) { y := new(uint256.Int).SetBytes(common.Hex2Bytes(param.y)) stack.push(x) stack.push(y) - opFn(&pc, evm.interpreter, &ScopeContext{nil, stack, nil}) + opFn(&pc, evm, &ScopeContext{nil, stack, nil}) actual := stack.pop() result[i] = TwoOperandTestcase{param.x, param.y, fmt.Sprintf("%064x", actual)} } @@ -296,7 +296,7 @@ func opBenchmark(bench *testing.B, op executionFunc, args ...string) { for _, arg := range intArgs { stack.push(arg) } - op(&pc, evm.interpreter, scope) + op(&pc, evm, scope) stack.pop() } bench.StopTimer() @@ -528,13 +528,13 @@ func TestOpMstore(t *testing.T) { v := "abcdef00000000000000abba000000000deaf000000c0de00100000000133700" stack.push(new(uint256.Int).SetBytes(common.Hex2Bytes(v))) stack.push(new(uint256.Int)) - opMstore(&pc, evm.interpreter, &ScopeContext{mem, stack, nil}) + opMstore(&pc, evm, &ScopeContext{mem, stack, nil}) if got := common.Bytes2Hex(mem.GetCopy(0, 32)); got != v { t.Fatalf("Mstore fail, got %v, expected %v", got, v) } stack.push(new(uint256.Int).SetUint64(0x1)) stack.push(new(uint256.Int)) - opMstore(&pc, evm.interpreter, &ScopeContext{mem, stack, nil}) + opMstore(&pc, evm, &ScopeContext{mem, stack, nil}) if common.Bytes2Hex(mem.GetCopy(0, 32)) != "0000000000000000000000000000000000000000000000000000000000000001" { t.Fatalf("Mstore failed to overwrite previous value") } @@ -555,7 +555,7 @@ func BenchmarkOpMstore(bench *testing.B) { for i := 0; i < bench.N; i++ { stack.push(value) stack.push(memStart) - opMstore(&pc, evm.interpreter, &ScopeContext{mem, stack, nil}) + opMstore(&pc, evm, &ScopeContext{mem, stack, nil}) } } @@ -581,14 +581,14 @@ func TestOpTstore(t *testing.T) { stack.push(new(uint256.Int).SetBytes(value)) // push the location to the stack stack.push(new(uint256.Int)) - opTstore(&pc, evm.interpreter, &scopeContext) + opTstore(&pc, evm, &scopeContext) // there should be no elements on the stack after TSTORE if stack.len() != 0 { t.Fatal("stack wrong size") } // push the location to the stack stack.push(new(uint256.Int)) - opTload(&pc, evm.interpreter, &scopeContext) + opTload(&pc, evm, &scopeContext) // there should be one element on the stack after TLOAD if stack.len() != 1 { t.Fatal("stack wrong size") @@ -613,7 +613,7 @@ func BenchmarkOpKeccak256(bench *testing.B) { for i := 0; i < bench.N; i++ { stack.push(uint256.NewInt(32)) stack.push(start) - opKeccak256(&pc, evm.interpreter, &ScopeContext{mem, stack, nil}) + opKeccak256(&pc, evm, &ScopeContext{mem, stack, nil}) } } @@ -707,7 +707,7 @@ func TestRandom(t *testing.T) { stack = newstack() pc = uint64(0) ) - opRandom(&pc, evm.interpreter, &ScopeContext{nil, stack, nil}) + opRandom(&pc, evm, &ScopeContext{nil, stack, nil}) if len(stack.data) != 1 { t.Errorf("Expected one item on stack after %v, got %d: ", tt.name, len(stack.data)) } @@ -749,7 +749,7 @@ func TestBlobHash(t *testing.T) { ) evm.SetTxContext(TxContext{BlobHashes: tt.hashes}) stack.push(uint256.NewInt(tt.idx)) - opBlobHash(&pc, evm.interpreter, &ScopeContext{nil, stack, nil}) + opBlobHash(&pc, evm, &ScopeContext{nil, stack, nil}) if len(stack.data) != 1 { t.Errorf("Expected one item on stack after %v, got %d: ", tt.name, len(stack.data)) } @@ -889,7 +889,7 @@ func TestOpMCopy(t *testing.T) { mem.Resize(memorySize) } // Do the copy - opMcopy(&pc, evm.interpreter, &ScopeContext{mem, stack, nil}) + opMcopy(&pc, evm, &ScopeContext{mem, stack, nil}) want := common.FromHex(strings.ReplaceAll(tc.want, " ", "")) if have := mem.store; !bytes.Equal(want, have) { t.Errorf("case %d: \nwant: %#x\nhave: %#x\n", i, want, have) @@ -1001,7 +1001,7 @@ func TestOpCLZ(t *testing.T) { } stack.push(val) - opCLZ(&pc, evm.interpreter, &ScopeContext{Stack: stack}) + opCLZ(&pc, evm, &ScopeContext{Stack: stack}) if gotLen := stack.len(); gotLen != 1 { t.Fatalf("stack length = %d; want 1", gotLen) diff --git a/core/vm/interpreter.go b/core/vm/interpreter.go index 34d19008da..a0637a6800 100644 --- a/core/vm/interpreter.go +++ b/core/vm/interpreter.go @@ -22,8 +22,6 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/math" "github.com/ethereum/go-ethereum/core/tracing" - "github.com/ethereum/go-ethereum/crypto" - "github.com/ethereum/go-ethereum/log" "github.com/holiman/uint256" ) @@ -89,93 +87,27 @@ func (ctx *ScopeContext) ContractCode() []byte { return ctx.Contract.Code } -// EVMInterpreter represents an EVM interpreter -type EVMInterpreter struct { - evm *EVM - table *JumpTable - - hasher crypto.KeccakState // Keccak256 hasher instance shared across opcodes - hasherBuf common.Hash // Keccak256 hasher result array shared across opcodes - - readOnly bool // Whether to throw on stateful modifications - returnData []byte // Last CALL's return data for subsequent reuse -} - -// NewEVMInterpreter returns a new instance of the Interpreter. -func NewEVMInterpreter(evm *EVM) *EVMInterpreter { - // If jump table was not initialised we set the default one. - var table *JumpTable - switch { - case evm.chainRules.IsOsaka: - table = &osakaInstructionSet - case evm.chainRules.IsVerkle: - // TODO replace with proper instruction set when fork is specified - table = &verkleInstructionSet - case evm.chainRules.IsPrague: - table = &pragueInstructionSet - case evm.chainRules.IsCancun: - table = &cancunInstructionSet - case evm.chainRules.IsShanghai: - table = &shanghaiInstructionSet - case evm.chainRules.IsMerge: - table = &mergeInstructionSet - case evm.chainRules.IsLondon: - table = &londonInstructionSet - case evm.chainRules.IsBerlin: - table = &berlinInstructionSet - case evm.chainRules.IsIstanbul: - table = &istanbulInstructionSet - case evm.chainRules.IsConstantinople: - table = &constantinopleInstructionSet - case evm.chainRules.IsByzantium: - table = &byzantiumInstructionSet - case evm.chainRules.IsEIP158: - table = &spuriousDragonInstructionSet - case evm.chainRules.IsEIP150: - table = &tangerineWhistleInstructionSet - case evm.chainRules.IsHomestead: - table = &homesteadInstructionSet - default: - table = &frontierInstructionSet - } - var extraEips []int - if len(evm.Config.ExtraEips) > 0 { - // Deep-copy jumptable to prevent modification of opcodes in other tables - table = copyJumpTable(table) - } - for _, eip := range evm.Config.ExtraEips { - if err := EnableEIP(eip, table); err != nil { - // Disable it, so caller can check if it's activated or not - log.Error("EIP activation failed", "eip", eip, "error", err) - } else { - extraEips = append(extraEips, eip) - } - } - evm.Config.ExtraEips = extraEips - return &EVMInterpreter{evm: evm, table: table, hasher: crypto.NewKeccakState()} -} - // Run loops and evaluates the contract's code with the given input data and returns // the return byte-slice and an error if one occurred. // // It's important to note that any errors returned by the interpreter should be // considered a revert-and-consume-all-gas operation except for // ErrExecutionReverted which means revert-and-keep-gas-left. -func (in *EVMInterpreter) Run(contract *Contract, input []byte, readOnly bool) (ret []byte, err error) { +func (evm *EVM) Run(contract *Contract, input []byte, readOnly bool) (ret []byte, err error) { // Increment the call depth which is restricted to 1024 - in.evm.depth++ - defer func() { in.evm.depth-- }() + evm.depth++ + defer func() { evm.depth-- }() // Make sure the readOnly is only set if we aren't in readOnly yet. // This also makes sure that the readOnly flag isn't removed for child calls. - if readOnly && !in.readOnly { - in.readOnly = true - defer func() { in.readOnly = false }() + if readOnly && !evm.readOnly { + evm.readOnly = true + defer func() { evm.readOnly = false }() } // Reset the previous call's return data. It's unimportant to preserve the old buffer // as every returning call will return new data anyway. - in.returnData = nil + evm.returnData = nil // Don't bother with the execution if there's no code. if len(contract.Code) == 0 { @@ -184,7 +116,7 @@ func (in *EVMInterpreter) Run(contract *Contract, input []byte, readOnly bool) ( var ( op OpCode // current opcode - jumpTable *JumpTable = in.table + jumpTable *JumpTable = evm.table mem = NewMemory() // bound memory stack = newstack() // local stack callContext = &ScopeContext{ @@ -198,11 +130,12 @@ func (in *EVMInterpreter) Run(contract *Contract, input []byte, readOnly bool) ( pc = uint64(0) // program counter cost uint64 // copies used by tracer - pcCopy uint64 // needed for the deferred EVMLogger - gasCopy uint64 // for EVMLogger to log gas remaining before execution - logged bool // deferred EVMLogger should ignore already logged steps - res []byte // result of the opcode execution function - debug = in.evm.Config.Tracer != nil + pcCopy uint64 // needed for the deferred EVMLogger + gasCopy uint64 // for EVMLogger to log gas remaining before execution + logged bool // deferred EVMLogger should ignore already logged steps + res []byte // result of the opcode execution function + debug = evm.Config.Tracer != nil + isEIP4762 = evm.chainRules.IsEIP4762 ) // Don't move this deferred function, it's placed before the OnOpcode-deferred method, // so that it gets executed _after_: the OnOpcode needs the stacks before @@ -218,11 +151,11 @@ func (in *EVMInterpreter) Run(contract *Contract, input []byte, readOnly bool) ( if err == nil { return } - if !logged && in.evm.Config.Tracer.OnOpcode != nil { - in.evm.Config.Tracer.OnOpcode(pcCopy, byte(op), gasCopy, cost, callContext, in.returnData, in.evm.depth, VMErrorFromErr(err)) + if !logged && evm.Config.Tracer.OnOpcode != nil { + evm.Config.Tracer.OnOpcode(pcCopy, byte(op), gasCopy, cost, callContext, evm.returnData, evm.depth, VMErrorFromErr(err)) } - if logged && in.evm.Config.Tracer.OnFault != nil { - in.evm.Config.Tracer.OnFault(pcCopy, byte(op), gasCopy, cost, callContext, in.evm.depth, VMErrorFromErr(err)) + if logged && evm.Config.Tracer.OnFault != nil { + evm.Config.Tracer.OnFault(pcCopy, byte(op), gasCopy, cost, callContext, evm.depth, VMErrorFromErr(err)) } }() } @@ -237,12 +170,12 @@ func (in *EVMInterpreter) Run(contract *Contract, input []byte, readOnly bool) ( logged, pcCopy, gasCopy = false, pc, contract.Gas } - if in.evm.chainRules.IsEIP4762 && !contract.IsDeployment && !contract.IsSystemCall { + if isEIP4762 && !contract.IsDeployment && !contract.IsSystemCall { // if the PC ends up in a new "chunk" of verkleized code, charge the // associated costs. contractAddr := contract.Address() - consumed, wanted := in.evm.TxContext.AccessEvents.CodeChunksRangeGas(contractAddr, pc, 1, uint64(len(contract.Code)), false, contract.Gas) - contract.UseGas(consumed, in.evm.Config.Tracer, tracing.GasChangeWitnessCodeChunk) + consumed, wanted := evm.TxContext.AccessEvents.CodeChunksRangeGas(contractAddr, pc, 1, uint64(len(contract.Code)), false, contract.Gas) + contract.UseGas(consumed, evm.Config.Tracer, tracing.GasChangeWitnessCodeChunk) if consumed < wanted { return nil, ErrOutOfGas } @@ -287,7 +220,7 @@ func (in *EVMInterpreter) Run(contract *Contract, input []byte, readOnly bool) ( // Consume the gas and return an error if not enough gas is available. // cost is explicitly set so that the capture state defer method can get the proper cost var dynamicCost uint64 - dynamicCost, err = operation.dynamicGas(in.evm, contract, stack, mem, memorySize) + dynamicCost, err = operation.dynamicGas(evm, contract, stack, mem, memorySize) cost += dynamicCost // for tracing if err != nil { return nil, fmt.Errorf("%w: %v", ErrOutOfGas, err) @@ -302,11 +235,11 @@ func (in *EVMInterpreter) Run(contract *Contract, input []byte, readOnly bool) ( // Do tracing before potential memory expansion if debug { - if in.evm.Config.Tracer.OnGasChange != nil { - in.evm.Config.Tracer.OnGasChange(gasCopy, gasCopy-cost, tracing.GasChangeCallOpCode) + if evm.Config.Tracer.OnGasChange != nil { + evm.Config.Tracer.OnGasChange(gasCopy, gasCopy-cost, tracing.GasChangeCallOpCode) } - if in.evm.Config.Tracer.OnOpcode != nil { - in.evm.Config.Tracer.OnOpcode(pc, byte(op), gasCopy, cost, callContext, in.returnData, in.evm.depth, VMErrorFromErr(err)) + if evm.Config.Tracer.OnOpcode != nil { + evm.Config.Tracer.OnOpcode(pc, byte(op), gasCopy, cost, callContext, evm.returnData, evm.depth, VMErrorFromErr(err)) logged = true } } @@ -315,7 +248,7 @@ func (in *EVMInterpreter) Run(contract *Contract, input []byte, readOnly bool) ( } // execute the operation - res, err = operation.execute(&pc, in, callContext) + res, err = operation.execute(&pc, evm, callContext) if err != nil { break } diff --git a/core/vm/jump_table.go b/core/vm/jump_table.go index 22eed8754f..d7a4d9da1d 100644 --- a/core/vm/jump_table.go +++ b/core/vm/jump_table.go @@ -23,7 +23,7 @@ import ( ) type ( - executionFunc func(pc *uint64, interpreter *EVMInterpreter, callContext *ScopeContext) ([]byte, error) + executionFunc func(pc *uint64, evm *EVM, callContext *ScopeContext) ([]byte, error) gasFunc func(*EVM, *Contract, *Stack, *Memory, uint64) (uint64, error) // last parameter is the requested memory size as a uint64 // memorySizeFunc returns the required size, and whether the operation overflowed a uint64 memorySizeFunc func(*Stack) (size uint64, overflow bool) diff --git a/eth/tracers/js/tracer_test.go b/eth/tracers/js/tracer_test.go index a12b990a93..7f376a27fc 100644 --- a/eth/tracers/js/tracer_test.go +++ b/eth/tracers/js/tracer_test.go @@ -65,7 +65,7 @@ func runTrace(tracer *tracers.Tracer, vmctx *vmContext, chaincfg *params.ChainCo tracer.OnTxStart(evm.GetVMContext(), types.NewTx(&types.LegacyTx{Gas: gasLimit, GasPrice: vmctx.txCtx.GasPrice}), contract.Caller()) tracer.OnEnter(0, byte(vm.CALL), contract.Caller(), contract.Address(), []byte{}, startGas, value.ToBig()) - ret, err := evm.Interpreter().Run(contract, []byte{}, false) + ret, err := evm.Run(contract, []byte{}, false) tracer.OnExit(0, ret, startGas-contract.Gas, err, true) // Rest gas assumes no refund tracer.OnTxEnd(&types.Receipt{GasUsed: gasLimit - contract.Gas}, nil) diff --git a/eth/tracers/logger/logger_test.go b/eth/tracers/logger/logger_test.go index 12000b3b9a..acc3069e70 100644 --- a/eth/tracers/logger/logger_test.go +++ b/eth/tracers/logger/logger_test.go @@ -52,7 +52,7 @@ func TestStoreCapture(t *testing.T) { contract.Code = []byte{byte(vm.PUSH1), 0x1, byte(vm.PUSH1), 0x0, byte(vm.SSTORE)} var index common.Hash logger.OnTxStart(evm.GetVMContext(), nil, common.Address{}) - _, err := evm.Interpreter().Run(contract, []byte{}, false) + _, err := evm.Run(contract, []byte{}, false) if err != nil { t.Fatal(err) } From 8ba1c791bf62838bbb7fe73abdad832e374b15dc Mon Sep 17 00:00:00 2001 From: kashitaka Date: Mon, 11 Aug 2025 15:29:07 +0900 Subject: [PATCH 30/57] ethclient: fix flaky pending tx test (#32380) Fixes: https://github.com/ethereum/go-ethereum/issues/32252 --- ethclient/ethclient_test.go | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/ethclient/ethclient_test.go b/ethclient/ethclient_test.go index 8e70177944..815bc29de4 100644 --- a/ethclient/ethclient_test.go +++ b/ethclient/ethclient_test.go @@ -110,6 +110,12 @@ func newTestBackend(config *node.Config) (*node.Node, []*types.Block, error) { if err != nil { return nil, nil, fmt.Errorf("can't create new ethereum service: %v", err) } + // Ensure tx pool starts the background operation + txPool := ethservice.TxPool() + if err = txPool.Sync(); err != nil { + return nil, nil, fmt.Errorf("can't sync transaction pool: %v", err) + } + // Import the test chain. if err := n.Start(); err != nil { return nil, nil, fmt.Errorf("can't start test node: %v", err) @@ -506,8 +512,9 @@ func testAtFunctions(t *testing.T, client *rpc.Client) { } // send a transaction for some interesting pending status - // and wait for the transaction to be included in the pending block - sendTransaction(ec) + if err := sendTransaction(ec); err != nil { + t.Fatalf("unexpected error: %v", err) + } // wait for the transaction to be included in the pending block for { From 18b4ee5972b38f27c471d423ae9a14fae7dca29e Mon Sep 17 00:00:00 2001 From: MozirDmitriy Date: Mon, 11 Aug 2025 09:32:27 +0300 Subject: [PATCH 31/57] ethdb/leveldb: check iterator error in Database.DeleteRange (#32384) Add missing it.Error() check after iteration in Database.DeleteRange to avoid silently ignoring iterator errors before writing the batch. Aligns behavior with batch.DeleteRange, which already validates iterator errors. No other functional changes; existing tests pass (TestLevelDB). --- ethdb/leveldb/leveldb.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/ethdb/leveldb/leveldb.go b/ethdb/leveldb/leveldb.go index 8e1bb86fec..b6c93907b1 100644 --- a/ethdb/leveldb/leveldb.go +++ b/ethdb/leveldb/leveldb.go @@ -233,6 +233,9 @@ func (db *Database) DeleteRange(start, end []byte) error { return err } } + if err := it.Error(); err != nil { + return err + } return batch.Write() } From 40072af04af3c967fb5d1358c334b9b005d9661a Mon Sep 17 00:00:00 2001 From: cui Date: Mon, 11 Aug 2025 15:00:11 +0800 Subject: [PATCH 32/57] core/vm: make types consistent in makeDup (#32378) --- core/vm/instructions.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/vm/instructions.go b/core/vm/instructions.go index fffa65fd6a..44d3e81a9c 100644 --- a/core/vm/instructions.go +++ b/core/vm/instructions.go @@ -1003,9 +1003,9 @@ func makePush(size uint64, pushByteSize int) executionFunc { } // make dup instruction function -func makeDup(size int64) executionFunc { +func makeDup(size int) executionFunc { return func(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) { - scope.Stack.dup(int(size)) + scope.Stack.dup(size) return nil, nil } } From 6238effeff1ef0f20f4b57188d6c021d7393a6e8 Mon Sep 17 00:00:00 2001 From: cui Date: Mon, 11 Aug 2025 18:05:06 +0800 Subject: [PATCH 33/57] miner: remove todo comment (#32389) see https://github.com/ethereum/go-ethereum/pull/32372#discussion_r2265885182 --- miner/worker.go | 1 - 1 file changed, 1 deletion(-) diff --git a/miner/worker.go b/miner/worker.go index ee31a65359..5405fb24b9 100644 --- a/miner/worker.go +++ b/miner/worker.go @@ -543,7 +543,6 @@ func totalFees(block *types.Block, receipts []*types.Receipt) *big.Int { for i, tx := range block.Transactions() { minerFee, _ := tx.EffectiveGasTip(block.BaseFee()) feesWei.Add(feesWei, new(big.Int).Mul(new(big.Int).SetUint64(receipts[i].GasUsed), minerFee)) - // TODO (MariusVanDerWijden) add blob fees } return feesWei } From 2485d096f33d1b073230ff9f53c5b5ebf9c293b5 Mon Sep 17 00:00:00 2001 From: sashass1315 Date: Mon, 11 Aug 2025 13:48:38 +0300 Subject: [PATCH 34/57] downloader: fix comment (#32382) The previous comment stated that every 3rd block has a tx and every 5th has an uncle. The implementation actually adds one transaction to every second block and does not add uncles. Updated the comment to reflect the real behavior to avoid confusion when reading tests. --- eth/downloader/queue_test.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/eth/downloader/queue_test.go b/eth/downloader/queue_test.go index 854acf3d8f..120e3f9d2d 100644 --- a/eth/downloader/queue_test.go +++ b/eth/downloader/queue_test.go @@ -36,13 +36,13 @@ import ( ) // makeChain creates a chain of n blocks starting at and including parent. -// the returned hash chain is ordered head->parent. In addition, every 3rd block -// contains a transaction and every 5th an uncle to allow testing correct block -// reassembly. +// The returned hash chain is ordered head->parent. +// If empty is false, every second block (i%2==0) contains one transaction. +// No uncles are added. func makeChain(n int, seed byte, parent *types.Block, empty bool) ([]*types.Block, []types.Receipts) { blocks, receipts := core.GenerateChain(params.TestChainConfig, parent, ethash.NewFaker(), testDB, n, func(i int, block *core.BlockGen) { block.SetCoinbase(common.Address{seed}) - // Add one tx to every secondblock + // Add one tx to every second block if !empty && i%2 == 0 { signer := types.MakeSigner(params.TestChainConfig, block.Number(), block.Timestamp()) tx, err := types.SignTx(types.NewTransaction(block.TxNonce(testAddress), common.Address{seed}, big.NewInt(1000), params.TxGas, block.BaseFee(), nil), signer, testKey) From 92106a6b17a2082caad94cecb96ca371d2cf4356 Mon Sep 17 00:00:00 2001 From: cui Date: Mon, 11 Aug 2025 20:24:55 +0800 Subject: [PATCH 35/57] accounts/abi, accounts/keystore: use reflect.TypeFor (#32323) Co-authored-by: Felix Lange --- accounts/abi/reflect.go | 24 ++++++++++++------------ accounts/abi/reflect_test.go | 4 ++-- accounts/abi/type.go | 20 ++++++++------------ accounts/keystore/keystore.go | 2 +- 4 files changed, 23 insertions(+), 27 deletions(-) diff --git a/accounts/abi/reflect.go b/accounts/abi/reflect.go index 729ca93c54..f6696ea978 100644 --- a/accounts/abi/reflect.go +++ b/accounts/abi/reflect.go @@ -53,7 +53,7 @@ func ConvertType(in interface{}, proto interface{}) interface{} { // indirect recursively dereferences the value until it either gets the value // or finds a big.Int func indirect(v reflect.Value) reflect.Value { - if v.Kind() == reflect.Ptr && v.Elem().Type() != reflect.TypeOf(big.Int{}) { + if v.Kind() == reflect.Ptr && v.Elem().Type() != reflect.TypeFor[big.Int]() { return indirect(v.Elem()) } return v @@ -65,32 +65,32 @@ func reflectIntType(unsigned bool, size int) reflect.Type { if unsigned { switch size { case 8: - return reflect.TypeOf(uint8(0)) + return reflect.TypeFor[uint8]() case 16: - return reflect.TypeOf(uint16(0)) + return reflect.TypeFor[uint16]() case 32: - return reflect.TypeOf(uint32(0)) + return reflect.TypeFor[uint32]() case 64: - return reflect.TypeOf(uint64(0)) + return reflect.TypeFor[uint64]() } } switch size { case 8: - return reflect.TypeOf(int8(0)) + return reflect.TypeFor[int8]() case 16: - return reflect.TypeOf(int16(0)) + return reflect.TypeFor[int16]() case 32: - return reflect.TypeOf(int32(0)) + return reflect.TypeFor[int32]() case 64: - return reflect.TypeOf(int64(0)) + return reflect.TypeFor[int64]() } - return reflect.TypeOf(&big.Int{}) + return reflect.TypeFor[*big.Int]() } // mustArrayToByteSlice creates a new byte slice with the exact same size as value // and copies the bytes in value to the new slice. func mustArrayToByteSlice(value reflect.Value) reflect.Value { - slice := reflect.MakeSlice(reflect.TypeOf([]byte{}), value.Len(), value.Len()) + slice := reflect.ValueOf(make([]byte, value.Len())) reflect.Copy(slice, value) return slice } @@ -104,7 +104,7 @@ func set(dst, src reflect.Value) error { switch { case dstType.Kind() == reflect.Interface && dst.Elem().IsValid() && (dst.Elem().Type().Kind() == reflect.Ptr || dst.Elem().CanSet()): return set(dst.Elem(), src) - case dstType.Kind() == reflect.Ptr && dstType.Elem() != reflect.TypeOf(big.Int{}): + case dstType.Kind() == reflect.Ptr && dstType.Elem() != reflect.TypeFor[big.Int](): return set(dst.Elem(), src) case srcType.AssignableTo(dstType) && dst.CanSet(): dst.Set(src) diff --git a/accounts/abi/reflect_test.go b/accounts/abi/reflect_test.go index 577fa6ca71..f5e509c52f 100644 --- a/accounts/abi/reflect_test.go +++ b/accounts/abi/reflect_test.go @@ -204,12 +204,12 @@ func TestConvertType(t *testing.T) { var fields []reflect.StructField fields = append(fields, reflect.StructField{ Name: "X", - Type: reflect.TypeOf(new(big.Int)), + Type: reflect.TypeFor[*big.Int](), Tag: "json:\"" + "x" + "\"", }) fields = append(fields, reflect.StructField{ Name: "Y", - Type: reflect.TypeOf(new(big.Int)), + Type: reflect.TypeFor[*big.Int](), Tag: "json:\"" + "y" + "\"", }) val := reflect.New(reflect.StructOf(fields)) diff --git a/accounts/abi/type.go b/accounts/abi/type.go index e59456f15a..2fd11ac123 100644 --- a/accounts/abi/type.go +++ b/accounts/abi/type.go @@ -238,9 +238,9 @@ func (t Type) GetType() reflect.Type { case UintTy: return reflectIntType(true, t.Size) case BoolTy: - return reflect.TypeOf(false) + return reflect.TypeFor[bool]() case StringTy: - return reflect.TypeOf("") + return reflect.TypeFor[string]() case SliceTy: return reflect.SliceOf(t.Elem.GetType()) case ArrayTy: @@ -248,19 +248,15 @@ func (t Type) GetType() reflect.Type { case TupleTy: return t.TupleType case AddressTy: - return reflect.TypeOf(common.Address{}) + return reflect.TypeFor[common.Address]() case FixedBytesTy: - return reflect.ArrayOf(t.Size, reflect.TypeOf(byte(0))) + return reflect.ArrayOf(t.Size, reflect.TypeFor[byte]()) case BytesTy: - return reflect.SliceOf(reflect.TypeOf(byte(0))) - case HashTy: - // hashtype currently not used - return reflect.ArrayOf(32, reflect.TypeOf(byte(0))) - case FixedPointTy: - // fixedpoint type currently not used - return reflect.ArrayOf(32, reflect.TypeOf(byte(0))) + return reflect.TypeFor[[]byte]() + case HashTy, FixedPointTy: // currently not used + return reflect.TypeFor[[32]byte]() case FunctionTy: - return reflect.ArrayOf(24, reflect.TypeOf(byte(0))) + return reflect.TypeFor[[24]byte]() default: panic("Invalid type") } diff --git a/accounts/keystore/keystore.go b/accounts/keystore/keystore.go index 3e85b0433b..fefba026ae 100644 --- a/accounts/keystore/keystore.go +++ b/accounts/keystore/keystore.go @@ -50,7 +50,7 @@ var ( ) // KeyStoreType is the reflect type of a keystore backend. -var KeyStoreType = reflect.TypeOf(&KeyStore{}) +var KeyStoreType = reflect.TypeFor[*KeyStore]() // KeyStoreScheme is the protocol scheme prefixing account and wallet URLs. const KeyStoreScheme = "keystore" From 55a471efaf6f0c3ac093c0923ffa089df438ece9 Mon Sep 17 00:00:00 2001 From: Forostovec Date: Mon, 11 Aug 2025 16:34:59 +0300 Subject: [PATCH 36/57] eth/downloader: skip nil peer in GetHeader (#32369) The GetHeader function was incorrectly returning an error when encountering nil peers in the peers list, which contradicted the comment "keep retrying if none are yet available". Changed the logic to skip nil peers with 'continue' instead of returning an error, allowing the function to properly iterate through all available peers and attempt to retrieve the target header from each valid peer. This ensures the function behaves as intended - trying all available peers before giving up, rather than failing on the first nil peer encountered. --- eth/downloader/beacondevsync.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/eth/downloader/beacondevsync.go b/eth/downloader/beacondevsync.go index 7b30684133..03f17b1a52 100644 --- a/eth/downloader/beacondevsync.go +++ b/eth/downloader/beacondevsync.go @@ -52,7 +52,8 @@ func (d *Downloader) GetHeader(hash common.Hash) (*types.Header, error) { for _, peer := range d.peers.peers { if peer == nil { - return nil, errors.New("could not find peer") + log.Warn("Encountered nil peer while retrieving sync target", "hash", hash) + continue } // Found a peer, attempt to retrieve the header whilst blocking and // retry if it fails for whatever reason From cbbf686ecc9e99f91886251f463dcea953913e1d Mon Sep 17 00:00:00 2001 From: rjl493456442 Date: Mon, 11 Aug 2025 21:55:38 +0800 Subject: [PATCH 37/57] trie, core: rework tracer and track origin value of dirty nodes (#32306) These changes made in the PR should be highlighted here The trie tracer is split into two distinct structs: opTracer and prevalueTracer. The former is specific to MPT, while the latter is generic and applicable to all trie implementations. The original values of dirty nodes are tracked in a NodeSet. This serves as the foundation for both full archive node implementations and the state live tracer. --- core/state/statedb.go | 6 +- trie/committer.go | 18 ++--- trie/proof.go | 7 +- trie/tracer.go | 136 +++++++++++++++++++++++-------------- trie/tracer_test.go | 49 ++++++------- trie/trie.go | 79 +++++++++++++-------- trie/trie_test.go | 42 ++++++------ trie/trienode/node.go | 82 +++++++++++++++++----- trie/trienode/node_test.go | 93 ++++++++++++++++++++++++- trie/verkle.go | 49 +++++++------ 10 files changed, 383 insertions(+), 178 deletions(-) diff --git a/core/state/statedb.go b/core/state/statedb.go index 7aa6780cfa..efb09a08a0 100644 --- a/core/state/statedb.go +++ b/core/state/statedb.go @@ -977,7 +977,7 @@ func (s *StateDB) fastDeleteStorage(snaps *snapshot.Tree, addrHash common.Hash, storageOrigins = make(map[common.Hash][]byte) // the set for tracking the original value of slot ) stack := trie.NewStackTrie(func(path []byte, hash common.Hash, blob []byte) { - nodes.AddNode(path, trienode.NewDeleted()) + nodes.AddNode(path, trienode.NewDeletedWithPrev(blob)) }) for iter.Next() { slot := common.CopyBytes(iter.Slot()) @@ -1028,7 +1028,7 @@ func (s *StateDB) slowDeleteStorage(addr common.Address, addrHash common.Hash, r if it.Hash() == (common.Hash{}) { continue } - nodes.AddNode(it.Path(), trienode.NewDeleted()) + nodes.AddNode(it.Path(), trienode.NewDeletedWithPrev(it.NodeBlob())) } if err := it.Error(); err != nil { return nil, nil, nil, err @@ -1160,7 +1160,7 @@ func (s *StateDB) commit(deleteEmptyObjects bool, noStorageWiping bool) (*stateU // // Given that some accounts may be destroyed and then recreated within // the same block, it's possible that a node set with the same owner - // may already exists. In such cases, these two sets are combined, with + // may already exist. In such cases, these two sets are combined, with // the later one overwriting the previous one if any nodes are modified // or deleted in both sets. // diff --git a/trie/committer.go b/trie/committer.go index 0939a07abb..a040868c6c 100644 --- a/trie/committer.go +++ b/trie/committer.go @@ -29,12 +29,12 @@ import ( // insertion order. type committer struct { nodes *trienode.NodeSet - tracer *tracer + tracer *prevalueTracer collectLeaf bool } // newCommitter creates a new committer or picks one from the pool. -func newCommitter(nodeset *trienode.NodeSet, tracer *tracer, collectLeaf bool) *committer { +func newCommitter(nodeset *trienode.NodeSet, tracer *prevalueTracer, collectLeaf bool) *committer { return &committer{ nodes: nodeset, tracer: tracer, @@ -110,14 +110,16 @@ func (c *committer) commitChildren(path []byte, n *fullNode, parallel bool) { } else { wg.Add(1) go func(index int) { + defer wg.Done() + p := append(path, byte(index)) childSet := trienode.NewNodeSet(c.nodes.Owner) childCommitter := newCommitter(childSet, c.tracer, c.collectLeaf) n.Children[index] = childCommitter.commit(p, child, false) + nodesMu.Lock() - c.nodes.MergeSet(childSet) + c.nodes.MergeDisjoint(childSet) nodesMu.Unlock() - wg.Done() }(i) } } @@ -140,15 +142,15 @@ func (c *committer) store(path []byte, n node) node { // The node is embedded in its parent, in other words, this node // will not be stored in the database independently, mark it as // deleted only if the node was existent in database before. - _, ok := c.tracer.accessList[string(path)] - if ok { - c.nodes.AddNode(path, trienode.NewDeleted()) + origin := c.tracer.get(path) + if len(origin) != 0 { + c.nodes.AddNode(path, trienode.NewDeletedWithPrev(origin)) } return n } // Collect the dirty node to nodeset for return. nhash := common.BytesToHash(hash) - c.nodes.AddNode(path, trienode.New(nhash, nodeToBytes(n))) + c.nodes.AddNode(path, trienode.NewNodeWithPrev(nhash, nodeToBytes(n), c.tracer.get(path))) // Collect the corresponding leaf node if it's required. We don't check // full node since it's impossible to store value in fullNode. The key diff --git a/trie/proof.go b/trie/proof.go index 53b7acc30c..f3ed417094 100644 --- a/trie/proof.go +++ b/trie/proof.go @@ -567,7 +567,12 @@ func VerifyRangeProof(rootHash common.Hash, firstKey []byte, keys [][]byte, valu } // Rebuild the trie with the leaf stream, the shape of trie // should be same with the original one. - tr := &Trie{root: root, reader: newEmptyReader(), tracer: newTracer()} + tr := &Trie{ + root: root, + reader: newEmptyReader(), + opTracer: newOpTracer(), + prevalueTracer: newPrevalueTracer(), + } if empty { tr.root = nil } diff --git a/trie/tracer.go b/trie/tracer.go index 90b9666f0b..206e8aa20d 100644 --- a/trie/tracer.go +++ b/trie/tracer.go @@ -18,14 +18,13 @@ package trie import ( "maps" - - "github.com/ethereum/go-ethereum/common" + "slices" ) -// tracer tracks the changes of trie nodes. During the trie operations, +// opTracer tracks the changes of trie nodes. During the trie operations, // some nodes can be deleted from the trie, while these deleted nodes // won't be captured by trie.Hasher or trie.Committer. Thus, these deleted -// nodes won't be removed from the disk at all. Tracer is an auxiliary tool +// nodes won't be removed from the disk at all. opTracer is an auxiliary tool // used to track all insert and delete operations of trie and capture all // deleted nodes eventually. // @@ -35,38 +34,25 @@ import ( // This tool can track all of them no matter the node is embedded in its // parent or not, but valueNode is never tracked. // -// Besides, it's also used for recording the original value of the nodes -// when they are resolved from the disk. The pre-value of the nodes will -// be used to construct trie history in the future. -// -// Note tracer is not thread-safe, callers should be responsible for handling +// Note opTracer is not thread-safe, callers should be responsible for handling // the concurrency issues by themselves. -type tracer struct { - inserts map[string]struct{} - deletes map[string]struct{} - accessList map[string][]byte +type opTracer struct { + inserts map[string]struct{} + deletes map[string]struct{} } -// newTracer initializes the tracer for capturing trie changes. -func newTracer() *tracer { - return &tracer{ - inserts: make(map[string]struct{}), - deletes: make(map[string]struct{}), - accessList: make(map[string][]byte), +// newOpTracer initializes the tracer for capturing trie changes. +func newOpTracer() *opTracer { + return &opTracer{ + inserts: make(map[string]struct{}), + deletes: make(map[string]struct{}), } } -// onRead tracks the newly loaded trie node and caches the rlp-encoded -// blob internally. Don't change the value outside of function since -// it's not deep-copied. -func (t *tracer) onRead(path []byte, val []byte) { - t.accessList[string(path)] = val -} - // onInsert tracks the newly inserted trie node. If it's already // in the deletion set (resurrected node), then just wipe it from // the deletion set as it's "untouched". -func (t *tracer) onInsert(path []byte) { +func (t *opTracer) onInsert(path []byte) { if _, present := t.deletes[string(path)]; present { delete(t.deletes, string(path)) return @@ -77,7 +63,7 @@ func (t *tracer) onInsert(path []byte) { // onDelete tracks the newly deleted trie node. If it's already // in the addition set, then just wipe it from the addition set // as it's untouched. -func (t *tracer) onDelete(path []byte) { +func (t *opTracer) onDelete(path []byte) { if _, present := t.inserts[string(path)]; present { delete(t.inserts, string(path)) return @@ -86,37 +72,83 @@ func (t *tracer) onDelete(path []byte) { } // reset clears the content tracked by tracer. -func (t *tracer) reset() { - t.inserts = make(map[string]struct{}) - t.deletes = make(map[string]struct{}) - t.accessList = make(map[string][]byte) +func (t *opTracer) reset() { + clear(t.inserts) + clear(t.deletes) } // copy returns a deep copied tracer instance. -func (t *tracer) copy() *tracer { - accessList := make(map[string][]byte, len(t.accessList)) - for path, blob := range t.accessList { - accessList[path] = common.CopyBytes(blob) - } - return &tracer{ - inserts: maps.Clone(t.inserts), - deletes: maps.Clone(t.deletes), - accessList: accessList, +func (t *opTracer) copy() *opTracer { + return &opTracer{ + inserts: maps.Clone(t.inserts), + deletes: maps.Clone(t.deletes), } } -// deletedNodes returns a list of node paths which are deleted from the trie. -func (t *tracer) deletedNodes() []string { - var paths []string +// deletedList returns a list of node paths which are deleted from the trie. +func (t *opTracer) deletedList() [][]byte { + paths := make([][]byte, 0, len(t.deletes)) for path := range t.deletes { - // It's possible a few deleted nodes were embedded - // in their parent before, the deletions can be no - // effect by deleting nothing, filter them out. - _, ok := t.accessList[path] - if !ok { - continue - } - paths = append(paths, path) + paths = append(paths, []byte(path)) } return paths } + +// prevalueTracer tracks the original values of resolved trie nodes. Cached trie +// node values are expected to be immutable. A zero-size node value is treated as +// non-existent and should not occur in practice. +// +// Note prevalueTracer is not thread-safe, callers should be responsible for +// handling the concurrency issues by themselves. +type prevalueTracer struct { + data map[string][]byte +} + +// newPrevalueTracer initializes the tracer for capturing resolved trie nodes. +func newPrevalueTracer() *prevalueTracer { + return &prevalueTracer{ + data: make(map[string][]byte), + } +} + +// put tracks the newly loaded trie node and caches its RLP-encoded +// blob internally. Do not modify the value outside this function, +// as it is not deep-copied. +func (t *prevalueTracer) put(path []byte, val []byte) { + t.data[string(path)] = val +} + +// get returns the cached trie node value. If the node is not found, nil will +// be returned. +func (t *prevalueTracer) get(path []byte) []byte { + return t.data[string(path)] +} + +// hasList returns a list of flags indicating whether the corresponding trie nodes +// specified by the path exist in the trie. +func (t *prevalueTracer) hasList(list [][]byte) []bool { + exists := make([]bool, 0, len(list)) + for _, path := range list { + _, ok := t.data[string(path)] + exists = append(exists, ok) + } + return exists +} + +// values returns a list of values of the cached trie nodes. +func (t *prevalueTracer) values() [][]byte { + return slices.Collect(maps.Values(t.data)) +} + +// reset resets the cached content in the prevalueTracer. +func (t *prevalueTracer) reset() { + clear(t.data) +} + +// copy returns a copied prevalueTracer instance. +func (t *prevalueTracer) copy() *prevalueTracer { + // Shadow clone is used, as the cached trie node values are immutable + return &prevalueTracer{ + data: maps.Clone(t.data), + } +} diff --git a/trie/tracer_test.go b/trie/tracer_test.go index 852a706021..f2a4287461 100644 --- a/trie/tracer_test.go +++ b/trie/tracer_test.go @@ -52,15 +52,15 @@ var ( } ) -func TestTrieTracer(t *testing.T) { - testTrieTracer(t, tiny) - testTrieTracer(t, nonAligned) - testTrieTracer(t, standard) +func TestTrieOpTracer(t *testing.T) { + testTrieOpTracer(t, tiny) + testTrieOpTracer(t, nonAligned) + testTrieOpTracer(t, standard) } // Tests if the trie diffs are tracked correctly. Tracer should capture // all non-leaf dirty nodes, no matter the node is embedded or not. -func testTrieTracer(t *testing.T, vals []struct{ k, v string }) { +func testTrieOpTracer(t *testing.T, vals []struct{ k, v string }) { db := newTestDatabase(rawdb.NewMemoryDatabase(), rawdb.HashScheme) trie := NewEmpty(db) @@ -68,8 +68,9 @@ func testTrieTracer(t *testing.T, vals []struct{ k, v string }) { for _, val := range vals { trie.MustUpdate([]byte(val.k), []byte(val.v)) } - insertSet := copySet(trie.tracer.inserts) // copy before commit - deleteSet := copySet(trie.tracer.deletes) // copy before commit + insertSet := copySet(trie.opTracer.inserts) // copy before commit + deleteSet := copySet(trie.opTracer.deletes) // copy before commit + root, nodes := trie.Commit(false) db.Update(root, types.EmptyRootHash, trienode.NewWithNodeSet(nodes)) @@ -86,7 +87,7 @@ func testTrieTracer(t *testing.T, vals []struct{ k, v string }) { for _, val := range vals { trie.MustDelete([]byte(val.k)) } - insertSet, deleteSet = copySet(trie.tracer.inserts), copySet(trie.tracer.deletes) + insertSet, deleteSet = copySet(trie.opTracer.inserts), copySet(trie.opTracer.deletes) if !compareSet(insertSet, nil) { t.Fatal("Unexpected insertion set") } @@ -97,13 +98,13 @@ func testTrieTracer(t *testing.T, vals []struct{ k, v string }) { // Test that after inserting a new batch of nodes and deleting them immediately, // the trie tracer should be cleared normally as no operation happened. -func TestTrieTracerNoop(t *testing.T) { - testTrieTracerNoop(t, tiny) - testTrieTracerNoop(t, nonAligned) - testTrieTracerNoop(t, standard) +func TestTrieOpTracerNoop(t *testing.T) { + testTrieOpTracerNoop(t, tiny) + testTrieOpTracerNoop(t, nonAligned) + testTrieOpTracerNoop(t, standard) } -func testTrieTracerNoop(t *testing.T, vals []struct{ k, v string }) { +func testTrieOpTracerNoop(t *testing.T, vals []struct{ k, v string }) { db := newTestDatabase(rawdb.NewMemoryDatabase(), rawdb.HashScheme) trie := NewEmpty(db) for _, val := range vals { @@ -112,22 +113,22 @@ func testTrieTracerNoop(t *testing.T, vals []struct{ k, v string }) { for _, val := range vals { trie.MustDelete([]byte(val.k)) } - if len(trie.tracer.inserts) != 0 { + if len(trie.opTracer.inserts) != 0 { t.Fatal("Unexpected insertion set") } - if len(trie.tracer.deletes) != 0 { + if len(trie.opTracer.deletes) != 0 { t.Fatal("Unexpected deletion set") } } -// Tests if the accessList is correctly tracked. -func TestAccessList(t *testing.T) { - testAccessList(t, tiny) - testAccessList(t, nonAligned) - testAccessList(t, standard) +// Tests if the original value of trie nodes are correctly tracked. +func TestPrevalueTracer(t *testing.T) { + testPrevalueTracer(t, tiny) + testPrevalueTracer(t, nonAligned) + testPrevalueTracer(t, standard) } -func testAccessList(t *testing.T, vals []struct{ k, v string }) { +func testPrevalueTracer(t *testing.T, vals []struct{ k, v string }) { var ( db = newTestDatabase(rawdb.NewMemoryDatabase(), rawdb.HashScheme) trie = NewEmpty(db) @@ -210,7 +211,7 @@ func testAccessList(t *testing.T, vals []struct{ k, v string }) { } // Tests origin values won't be tracked in Iterator or Prover -func TestAccessListLeak(t *testing.T) { +func TestPrevalueTracerLeak(t *testing.T) { var ( db = newTestDatabase(rawdb.NewMemoryDatabase(), rawdb.HashScheme) trie = NewEmpty(db) @@ -249,9 +250,9 @@ func TestAccessListLeak(t *testing.T) { } for _, c := range cases { trie, _ = New(TrieID(root), db) - n1 := len(trie.tracer.accessList) + n1 := len(trie.prevalueTracer.data) c.op(trie) - n2 := len(trie.tracer.accessList) + n2 := len(trie.prevalueTracer.data) if n1 != n2 { t.Fatalf("AccessList is leaked, prev %d after %d", n1, n2) diff --git a/trie/trie.go b/trie/trie.go index 222bf8b1f0..57c47b8ac9 100644 --- a/trie/trie.go +++ b/trie/trie.go @@ -55,8 +55,9 @@ type Trie struct { // reader is the handler trie can retrieve nodes from. reader *trieReader - // tracer is the tool to track the trie changes. - tracer *tracer + // Various tracers for capturing the modifications to trie + opTracer *opTracer + prevalueTracer *prevalueTracer } // newFlag returns the cache flag value for a newly created node. @@ -67,13 +68,14 @@ func (t *Trie) newFlag() nodeFlag { // Copy returns a copy of Trie. func (t *Trie) Copy() *Trie { return &Trie{ - root: copyNode(t.root), - owner: t.owner, - committed: t.committed, - unhashed: t.unhashed, - uncommitted: t.uncommitted, - reader: t.reader, - tracer: t.tracer.copy(), + root: copyNode(t.root), + owner: t.owner, + committed: t.committed, + unhashed: t.unhashed, + uncommitted: t.uncommitted, + reader: t.reader, + opTracer: t.opTracer.copy(), + prevalueTracer: t.prevalueTracer.copy(), } } @@ -89,9 +91,10 @@ func New(id *ID, db database.NodeDatabase) (*Trie, error) { return nil, err } trie := &Trie{ - owner: id.Owner, - reader: reader, - tracer: newTracer(), + owner: id.Owner, + reader: reader, + opTracer: newOpTracer(), + prevalueTracer: newPrevalueTracer(), } if id.Root != (common.Hash{}) && id.Root != types.EmptyRootHash { rootnode, err := trie.resolveAndTrack(id.Root[:], nil) @@ -361,7 +364,7 @@ func (t *Trie) insert(n node, prefix, key []byte, value node) (bool, node, error // New branch node is created as a child of the original short node. // Track the newly inserted node in the tracer. The node identifier // passed is the path from the root node. - t.tracer.onInsert(append(prefix, key[:matchlen]...)) + t.opTracer.onInsert(append(prefix, key[:matchlen]...)) // Replace it with a short node leading up to the branch. return true, &shortNode{key[:matchlen], branch, t.newFlag()}, nil @@ -379,7 +382,7 @@ func (t *Trie) insert(n node, prefix, key []byte, value node) (bool, node, error // New short node is created and track it in the tracer. The node identifier // passed is the path from the root node. Note the valueNode won't be tracked // since it's always embedded in its parent. - t.tracer.onInsert(prefix) + t.opTracer.onInsert(prefix) return true, &shortNode{key, value, t.newFlag()}, nil @@ -444,7 +447,7 @@ func (t *Trie) delete(n node, prefix, key []byte) (bool, node, error) { // The matched short node is deleted entirely and track // it in the deletion set. The same the valueNode doesn't // need to be tracked at all since it's always embedded. - t.tracer.onDelete(prefix) + t.opTracer.onDelete(prefix) return true, nil, nil // remove n entirely for whole matches } @@ -460,7 +463,7 @@ func (t *Trie) delete(n node, prefix, key []byte) (bool, node, error) { case *shortNode: // The child shortNode is merged into its parent, track // is deleted as well. - t.tracer.onDelete(append(prefix, n.Key...)) + t.opTracer.onDelete(append(prefix, n.Key...)) // Deleting from the subtrie reduced it to another // short node. Merge the nodes to avoid creating a @@ -525,7 +528,7 @@ func (t *Trie) delete(n node, prefix, key []byte) (bool, node, error) { // Replace the entire full node with the short node. // Mark the original short node as deleted since the // value is embedded into the parent now. - t.tracer.onDelete(append(prefix, byte(pos))) + t.opTracer.onDelete(append(prefix, byte(pos))) k := append([]byte{byte(pos)}, cnode.Key...) return true, &shortNode{k, cnode.Val, t.newFlag()}, nil @@ -616,13 +619,31 @@ func (t *Trie) resolveAndTrack(n hashNode, prefix []byte) (node, error) { if err != nil { return nil, err } - t.tracer.onRead(prefix, blob) + t.prevalueTracer.put(prefix, blob) // The returned node blob won't be changed afterward. No need to // deep-copy the slice. return decodeNodeUnsafe(n, blob) } +// deletedNodes returns a list of node paths, referring the nodes being deleted +// from the trie. It's possible a few deleted nodes were embedded in their parent +// before, the deletions can be no effect by deleting nothing, filter them out. +func (t *Trie) deletedNodes() [][]byte { + var ( + pos int + list = t.opTracer.deletedList() + flags = t.prevalueTracer.hasList(list) + ) + for i := 0; i < len(list); i++ { + if flags[i] { + list[pos] = list[i] + pos++ + } + } + return list[:pos] // trim to the new length +} + // Hash returns the root hash of the trie. It does not write to the // database and can be used even if the trie doesn't have one. func (t *Trie) Hash() common.Hash { @@ -644,13 +665,13 @@ func (t *Trie) Commit(collectLeaf bool) (common.Hash, *trienode.NodeSet) { // (b) The trie was non-empty and all nodes are dropped => return // the node set includes all deleted nodes if t.root == nil { - paths := t.tracer.deletedNodes() + paths := t.deletedNodes() if len(paths) == 0 { return types.EmptyRootHash, nil // case (a) } nodes := trienode.NewNodeSet(t.owner) for _, path := range paths { - nodes.AddNode([]byte(path), trienode.NewDeleted()) + nodes.AddNode(path, trienode.NewDeletedWithPrev(t.prevalueTracer.get(path))) } return types.EmptyRootHash, nodes // case (b) } @@ -667,11 +688,11 @@ func (t *Trie) Commit(collectLeaf bool) (common.Hash, *trienode.NodeSet) { return rootHash, nil } nodes := trienode.NewNodeSet(t.owner) - for _, path := range t.tracer.deletedNodes() { - nodes.AddNode([]byte(path), trienode.NewDeleted()) + for _, path := range t.deletedNodes() { + nodes.AddNode(path, trienode.NewDeletedWithPrev(t.prevalueTracer.get(path))) } // If the number of changes is below 100, we let one thread handle it - t.root = newCommitter(nodes, t.tracer, collectLeaf).Commit(t.root, t.uncommitted > 100) + t.root = newCommitter(nodes, t.prevalueTracer, collectLeaf).Commit(t.root, t.uncommitted > 100) t.uncommitted = 0 return rootHash, nodes } @@ -692,12 +713,13 @@ func (t *Trie) hashRoot() []byte { // Witness returns a set containing all trie nodes that have been accessed. func (t *Trie) Witness() map[string]struct{} { - if len(t.tracer.accessList) == 0 { + values := t.prevalueTracer.values() + if len(values) == 0 { return nil } - witness := make(map[string]struct{}, len(t.tracer.accessList)) - for _, node := range t.tracer.accessList { - witness[string(node)] = struct{}{} + witness := make(map[string]struct{}, len(values)) + for _, val := range values { + witness[string(val)] = struct{}{} } return witness } @@ -708,6 +730,7 @@ func (t *Trie) Reset() { t.owner = common.Hash{} t.unhashed = 0 t.uncommitted = 0 - t.tracer.reset() + t.opTracer.reset() + t.prevalueTracer.reset() t.committed = false } diff --git a/trie/trie_test.go b/trie/trie_test.go index edd85677fe..68759c37c0 100644 --- a/trie/trie_test.go +++ b/trie/trie_test.go @@ -449,35 +449,35 @@ func verifyAccessList(old *Trie, new *Trie, set *trienode.NodeSet) error { if !ok || n.IsDeleted() { return errors.New("expect new node") } - //if len(n.Prev) > 0 { - // return errors.New("unexpected origin value") - //} + if len(set.Origins[path]) > 0 { + return errors.New("unexpected origin value") + } } // Check deletion set - for path := range deletes { + for path, blob := range deletes { n, ok := set.Nodes[path] if !ok || !n.IsDeleted() { return errors.New("expect deleted node") } - //if len(n.Prev) == 0 { - // return errors.New("expect origin value") - //} - //if !bytes.Equal(n.Prev, blob) { - // return errors.New("invalid origin value") - //} + if len(set.Origins[path]) == 0 { + return errors.New("expect origin value") + } + if !bytes.Equal(set.Origins[path], blob) { + return errors.New("invalid origin value") + } } // Check update set - for path := range updates { + for path, blob := range updates { n, ok := set.Nodes[path] if !ok || n.IsDeleted() { return errors.New("expect updated node") } - //if len(n.Prev) == 0 { - // return errors.New("expect origin value") - //} - //if !bytes.Equal(n.Prev, blob) { - // return errors.New("invalid origin value") - //} + if len(set.Origins[path]) == 0 { + return errors.New("expect origin value") + } + if !bytes.Equal(set.Origins[path], blob) { + return errors.New("invalid origin value") + } } return nil } @@ -595,18 +595,18 @@ func runRandTest(rt randTest) error { deleteExp[path] = struct{}{} } } - if len(insertExp) != len(tr.tracer.inserts) { + if len(insertExp) != len(tr.opTracer.inserts) { rt[i].err = errors.New("insert set mismatch") } - if len(deleteExp) != len(tr.tracer.deletes) { + if len(deleteExp) != len(tr.opTracer.deletes) { rt[i].err = errors.New("delete set mismatch") } - for insert := range tr.tracer.inserts { + for insert := range tr.opTracer.inserts { if _, present := insertExp[insert]; !present { rt[i].err = errors.New("missing inserted node") } } - for del := range tr.tracer.deletes { + for del := range tr.opTracer.deletes { if _, present := deleteExp[del]; !present { rt[i].err = errors.New("missing deleted node") } diff --git a/trie/trienode/node.go b/trie/trienode/node.go index b09ec66374..c83dc27cef 100644 --- a/trie/trienode/node.go +++ b/trie/trienode/node.go @@ -51,6 +51,35 @@ func New(hash common.Hash, blob []byte) *Node { // NewDeleted constructs a node which is deleted. func NewDeleted() *Node { return New(common.Hash{}, nil) } +// NodeWithPrev is a wrapper over Node by tracking the original value of node. +type NodeWithPrev struct { + *Node + Prev []byte // Nil means the node was not existent +} + +// NewNodeWithPrev constructs a node with the additional original value. +func NewNodeWithPrev(hash common.Hash, blob []byte, prev []byte) *NodeWithPrev { + return &NodeWithPrev{ + Node: &Node{ + Hash: hash, + Blob: blob, + }, + Prev: prev, + } +} + +// NewDeletedWithPrev constructs a node which is deleted with the additional +// original value. +func NewDeletedWithPrev(prev []byte) *NodeWithPrev { + return &NodeWithPrev{ + Node: &Node{ + Hash: common.Hash{}, + Blob: nil, + }, + Prev: prev, + } +} + // leaf represents a trie leaf node type leaf struct { Blob []byte // raw blob of leaf @@ -63,6 +92,8 @@ type NodeSet struct { Owner common.Hash Leaves []*leaf Nodes map[string]*Node + Origins map[string][]byte + updates int // the count of updated and inserted nodes deletes int // the count of deleted nodes } @@ -71,8 +102,9 @@ type NodeSet struct { // the owning account address hash for storage tries. func NewNodeSet(owner common.Hash) *NodeSet { return &NodeSet{ - Owner: owner, - Nodes: make(map[string]*Node), + Owner: owner, + Nodes: make(map[string]*Node), + Origins: make(map[string][]byte), } } @@ -91,22 +123,25 @@ func (set *NodeSet) ForEachWithOrder(callback func(path string, n *Node)) { } // AddNode adds the provided node into set. -func (set *NodeSet) AddNode(path []byte, n *Node) { +func (set *NodeSet) AddNode(path []byte, n *NodeWithPrev) { if n.IsDeleted() { set.deletes += 1 } else { set.updates += 1 } - set.Nodes[string(path)] = n + key := string(path) + set.Nodes[key] = n.Node + set.Origins[key] = n.Prev } -// MergeSet merges this 'set' with 'other'. It assumes that the sets are disjoint, +// MergeDisjoint merges this 'set' with 'other'. It assumes that the sets are disjoint, // and thus does not deduplicate data (count deletes, dedup leaves etc). -func (set *NodeSet) MergeSet(other *NodeSet) error { +func (set *NodeSet) MergeDisjoint(other *NodeSet) error { if set.Owner != other.Owner { return fmt.Errorf("nodesets belong to different owner are not mergeable %x-%x", set.Owner, other.Owner) } maps.Copy(set.Nodes, other.Nodes) + maps.Copy(set.Origins, other.Origins) set.deletes += other.deletes set.updates += other.updates @@ -117,12 +152,13 @@ func (set *NodeSet) MergeSet(other *NodeSet) error { return nil } -// Merge adds a set of nodes into the set. -func (set *NodeSet) Merge(owner common.Hash, nodes map[string]*Node) error { - if set.Owner != owner { - return fmt.Errorf("nodesets belong to different owner are not mergeable %x-%x", set.Owner, owner) +// Merge adds a set of nodes to the current set. It assumes the sets may overlap, +// so deduplication is performed. +func (set *NodeSet) Merge(other *NodeSet) error { + if set.Owner != other.Owner { + return fmt.Errorf("nodesets belong to different owner are not mergeable %x-%x", set.Owner, other.Owner) } - for path, node := range nodes { + for path, node := range other.Nodes { prev, ok := set.Nodes[path] if ok { // overwrite happens, revoke the counter @@ -137,8 +173,17 @@ func (set *NodeSet) Merge(owner common.Hash, nodes map[string]*Node) error { } else { set.updates += 1 } - set.Nodes[path] = node + set.Nodes[path] = node // overwrite the node with new value + + // Add the original value only if it was previously non-existent. + // If multiple mutations are made to the same node, the first one + // is considered the true original value. + if _, exist := set.Origins[path]; !exist { + set.Origins[path] = other.Origins[path] + } } + // TODO leaves are not aggregated, as they are not used in storage tries. + // TODO(rjl493456442) deprecate the leaves along with the legacy hash mode. return nil } @@ -169,11 +214,16 @@ func (set *NodeSet) Summary() string { for path, n := range set.Nodes { // Deletion if n.IsDeleted() { - fmt.Fprintf(out, " [-]: %x\n", path) + fmt.Fprintf(out, " [-]: %x prev: %x\n", path, set.Origins[path]) continue } - // Insertion or update - fmt.Fprintf(out, " [+/*]: %x -> %v \n", path, n.Hash) + // Insertion + if len(set.Origins[path]) == 0 { + fmt.Fprintf(out, " [+]: %x -> %v\n", path, n.Hash) + continue + } + // Update + fmt.Fprintf(out, " [*]: %x -> %v prev: %x\n", path, n.Hash, set.Origins[path]) } for _, n := range set.Leaves { fmt.Fprintf(out, "[leaf]: %v\n", n) @@ -203,7 +253,7 @@ func NewWithNodeSet(set *NodeSet) *MergedNodeSet { func (set *MergedNodeSet) Merge(other *NodeSet) error { subset, present := set.Sets[other.Owner] if present { - return subset.Merge(other.Owner, other.Nodes) + return subset.Merge(other) } set.Sets[other.Owner] = other return nil diff --git a/trie/trienode/node_test.go b/trie/trienode/node_test.go index bcb3a2202b..332b6f1776 100644 --- a/trie/trienode/node_test.go +++ b/trie/trienode/node_test.go @@ -17,13 +17,100 @@ package trienode import ( + "bytes" "crypto/rand" + "maps" + "reflect" + "slices" "testing" + "github.com/davecgh/go-spew/spew" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/internal/testrand" ) +func makeTestSet(owner common.Hash, n int, paths [][]byte) *NodeSet { + set := NewNodeSet(owner) + for i := 0; i < n*3/4; i++ { + path := testrand.Bytes(10) + blob := testrand.Bytes(100) + set.AddNode(path, NewNodeWithPrev(crypto.Keccak256Hash(blob), blob, testrand.Bytes(100))) + } + for i := 0; i < n/4; i++ { + path := testrand.Bytes(10) + set.AddNode(path, NewDeletedWithPrev(testrand.Bytes(100))) + } + for i := 0; i < len(paths); i++ { + if i%3 == 0 { + set.AddNode(paths[i], NewDeletedWithPrev(testrand.Bytes(100))) + } else { + blob := testrand.Bytes(100) + set.AddNode(paths[i], NewNodeWithPrev(crypto.Keccak256Hash(blob), blob, testrand.Bytes(100))) + } + } + return set +} + +func copyNodeSet(set *NodeSet) *NodeSet { + cpy := &NodeSet{ + Owner: set.Owner, + Leaves: slices.Clone(set.Leaves), + updates: set.updates, + deletes: set.deletes, + Nodes: maps.Clone(set.Nodes), + Origins: maps.Clone(set.Origins), + } + return cpy +} + +func TestNodeSetMerge(t *testing.T) { + var shared [][]byte + for i := 0; i < 2; i++ { + shared = append(shared, testrand.Bytes(10)) + } + owner := testrand.Hash() + setA := makeTestSet(owner, 20, shared) + cpyA := copyNodeSet(setA) + + setB := makeTestSet(owner, 20, shared) + setA.Merge(setB) + + for path, node := range setA.Nodes { + nA, inA := cpyA.Nodes[path] + nB, inB := setB.Nodes[path] + + switch { + case inA && inB: + origin := setA.Origins[path] + if !bytes.Equal(origin, cpyA.Origins[path]) { + t.Errorf("Unexpected origin, path %v: want: %v, got: %v", []byte(path), cpyA.Origins[path], origin) + } + if !reflect.DeepEqual(node, nB) { + t.Errorf("Unexpected node, path %v: want: %v, got: %v", []byte(path), spew.Sdump(nB), spew.Sdump(node)) + } + case !inA && inB: + origin := setA.Origins[path] + if !bytes.Equal(origin, setB.Origins[path]) { + t.Errorf("Unexpected origin, path %v: want: %v, got: %v", []byte(path), setB.Origins[path], origin) + } + if !reflect.DeepEqual(node, nB) { + t.Errorf("Unexpected node, path %v: want: %v, got: %v", []byte(path), spew.Sdump(nB), spew.Sdump(node)) + } + case inA && !inB: + origin := setA.Origins[path] + if !bytes.Equal(origin, cpyA.Origins[path]) { + t.Errorf("Unexpected origin, path %v: want: %v, got: %v", []byte(path), cpyA.Origins[path], origin) + } + if !reflect.DeepEqual(node, nA) { + t.Errorf("Unexpected node, path %v: want: %v, got: %v", []byte(path), spew.Sdump(nA), spew.Sdump(node)) + } + default: + t.Errorf("Unexpected node, %v", []byte(path)) + } + } +} + func BenchmarkMerge(b *testing.B) { b.Run("1K", func(b *testing.B) { benchmarkMerge(b, 1000) @@ -42,7 +129,7 @@ func benchmarkMerge(b *testing.B, count int) { blob := make([]byte, 32) rand.Read(blob) hash := crypto.Keccak256Hash(blob) - s.AddNode(path, New(hash, blob)) + s.AddNode(path, NewNodeWithPrev(hash, blob, nil)) } for i := 0; i < count; i++ { // Random path of 4 nibbles @@ -53,9 +140,9 @@ func benchmarkMerge(b *testing.B, count int) { for i := 0; i < b.N; i++ { // Store set x into a backup z := NewNodeSet(common.Hash{}) - z.Merge(common.Hash{}, x.Nodes) + z.Merge(x) // Merge y into x - x.Merge(common.Hash{}, y.Nodes) + x.Merge(y) x = z } } diff --git a/trie/verkle.go b/trie/verkle.go index 015b8f6590..c89a8f1d36 100644 --- a/trie/verkle.go +++ b/trie/verkle.go @@ -42,6 +42,7 @@ type VerkleTrie struct { root verkle.VerkleNode cache *utils.PointCache reader *trieReader + tracer *prevalueTracer } // NewVerkleTrie constructs a verkle tree based on the specified root hash. @@ -50,27 +51,25 @@ func NewVerkleTrie(root common.Hash, db database.NodeDatabase, cache *utils.Poin if err != nil { return nil, err } - // Parse the root verkle node if it's not empty. - node := verkle.New() - if root != types.EmptyVerkleHash && root != types.EmptyRootHash { - blob, err := reader.node(nil, common.Hash{}) - if err != nil { - return nil, err - } - node, err = verkle.ParseNode(blob, 0) - if err != nil { - return nil, err - } - } - return &VerkleTrie{ - root: node, + t := &VerkleTrie{ + root: verkle.New(), cache: cache, reader: reader, - }, nil -} - -func (t *VerkleTrie) FlatdbNodeResolver(path []byte) ([]byte, error) { - return t.reader.node(path, common.Hash{}) + tracer: newPrevalueTracer(), + } + // Parse the root verkle node if it's not empty. + if root != types.EmptyVerkleHash && root != types.EmptyRootHash { + blob, err := t.nodeResolver(nil) + if err != nil { + return nil, err + } + node, err := verkle.ParseNode(blob, 0) + if err != nil { + return nil, err + } + t.root = node + } + return t, nil } // GetKey returns the sha3 preimage of a hashed key that was previously used @@ -268,7 +267,7 @@ func (t *VerkleTrie) Commit(_ bool) (common.Hash, *trienode.NodeSet) { nodeset := trienode.NewNodeSet(common.Hash{}) for _, node := range nodes { // Hash parameter is not used in pathdb - nodeset.AddNode(node.Path, trienode.New(common.Hash{}, node.SerializedBytes)) + nodeset.AddNode(node.Path, trienode.NewNodeWithPrev(common.Hash{}, node.SerializedBytes, t.tracer.get(node.Path))) } // Serialize root commitment form return t.Hash(), nodeset @@ -301,6 +300,7 @@ func (t *VerkleTrie) Copy() *VerkleTrie { root: t.root.Copy(), cache: t.cache, reader: t.reader, + tracer: t.tracer.copy(), } } @@ -317,7 +317,7 @@ func (t *VerkleTrie) Proof(posttrie *VerkleTrie, keys [][]byte) (*verkle.VerkleP if posttrie != nil { postroot = posttrie.root } - proof, _, _, _, err := verkle.MakeVerkleMultiProof(t.root, postroot, keys, t.FlatdbNodeResolver) + proof, _, _, _, err := verkle.MakeVerkleMultiProof(t.root, postroot, keys, t.nodeResolver) if err != nil { return nil, nil, err } @@ -421,7 +421,12 @@ func (t *VerkleTrie) ToDot() string { } func (t *VerkleTrie) nodeResolver(path []byte) ([]byte, error) { - return t.reader.node(path, common.Hash{}) + blob, err := t.reader.node(path, common.Hash{}) + if err != nil { + return nil, err + } + t.tracer.put(path, blob) + return blob, nil } // Witness returns a set containing all trie nodes that have been accessed. From 2e9c9b5e981595a24ac75baae64999b86060b5bd Mon Sep 17 00:00:00 2001 From: Rizky Ikwan Date: Tue, 12 Aug 2025 14:11:18 +0200 Subject: [PATCH 38/57] consensus: fix ambiguous invalid gas limit error (#32405) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Description Correct symmetric tolerance in gas limit validation: Replace ambiguous "+-=" with standard "+/-" in the error message. Logic rejects when |header − parent| ≥ limit, so allowed range is |Δ| ≤ limit − 1. No logic or functionality has been modified. --- consensus/misc/gaslimit.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/consensus/misc/gaslimit.go b/consensus/misc/gaslimit.go index dfcabd9a80..9ae8c95f4b 100644 --- a/consensus/misc/gaslimit.go +++ b/consensus/misc/gaslimit.go @@ -32,7 +32,7 @@ func VerifyGaslimit(parentGasLimit, headerGasLimit uint64) error { } limit := parentGasLimit / params.GasLimitBoundDivisor if uint64(diff) >= limit { - return fmt.Errorf("invalid gas limit: have %d, want %d +-= %d", headerGasLimit, parentGasLimit, limit-1) + return fmt.Errorf("invalid gas limit: have %d, want %d +/- %d", headerGasLimit, parentGasLimit, limit-1) } if headerGasLimit < params.MinGasLimit { return fmt.Errorf("invalid gas limit below %d", params.MinGasLimit) From 43b2aac33c6c464cd30e5886a5ef8521122ad295 Mon Sep 17 00:00:00 2001 From: cui Date: Tue, 12 Aug 2025 21:47:18 +0800 Subject: [PATCH 39/57] trie: refactor to use slices.Concat (#32401) --- trie/trie.go | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/trie/trie.go b/trie/trie.go index 57c47b8ac9..307036faa9 100644 --- a/trie/trie.go +++ b/trie/trie.go @@ -21,6 +21,7 @@ import ( "bytes" "errors" "fmt" + "slices" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" @@ -471,7 +472,7 @@ func (t *Trie) delete(n node, prefix, key []byte) (bool, node, error) { // always creates a new slice) instead of append to // avoid modifying n.Key since it might be shared with // other nodes. - return true, &shortNode{concat(n.Key, child.Key...), child.Val, t.newFlag()}, nil + return true, &shortNode{slices.Concat(n.Key, child.Key), child.Val, t.newFlag()}, nil default: return true, &shortNode{n.Key, child, t.newFlag()}, nil } @@ -566,13 +567,6 @@ func (t *Trie) delete(n node, prefix, key []byte) (bool, node, error) { } } -func concat(s1 []byte, s2 ...byte) []byte { - r := make([]byte, len(s1)+len(s2)) - copy(r, s1) - copy(r[len(s1):], s2) - return r -} - // copyNode deep-copies the supplied node along with its children recursively. func copyNode(n node) node { switch n := (n).(type) { From 56edd21453bf9f055202a7bd8c56aa36aa87dab0 Mon Sep 17 00:00:00 2001 From: youzichuan Date: Wed, 13 Aug 2025 01:37:09 +0800 Subject: [PATCH 40/57] cmd: fix inconsistent function name in comment (#32411) fix inconsistent function name in comment Signed-off-by: youzichuan --- cmd/geth/chaincmd.go | 2 +- cmd/workload/filtertest.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/cmd/geth/chaincmd.go b/cmd/geth/chaincmd.go index 112d1a539b..d0f4d6f81d 100644 --- a/cmd/geth/chaincmd.go +++ b/cmd/geth/chaincmd.go @@ -704,7 +704,7 @@ func pruneHistory(ctx *cli.Context) error { return nil } -// downladEra is the era1 file downloader tool. +// downloadEra is the era1 file downloader tool. func downloadEra(ctx *cli.Context) error { flags.CheckExclusive(ctx, eraBlockFlag, eraEpochFlag, eraAllFlag) diff --git a/cmd/workload/filtertest.go b/cmd/workload/filtertest.go index 11062122b8..9f0b6cab44 100644 --- a/cmd/workload/filtertest.go +++ b/cmd/workload/filtertest.go @@ -92,7 +92,7 @@ func (s *filterTestSuite) filterShortRange(t *utesting.T) { }, s.queryAndCheck) } -// filterShortRange runs all long-range filter tests. +// filterLongRange runs all long-range filter tests. func (s *filterTestSuite) filterLongRange(t *utesting.T) { s.filterRange(t, func(query *filterQuery) bool { return query.ToBlock+1-query.FromBlock > filterRangeThreshold From 75fc56f27d5b460f396f6db06f65221cbd0c9ff2 Mon Sep 17 00:00:00 2001 From: Klimov Sergei Date: Wed, 13 Aug 2025 15:02:50 +0800 Subject: [PATCH 41/57] eth: abort `requiredBlocks` check if peer handler terminated (#32413) --- eth/handler.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/eth/handler.go b/eth/handler.go index 033a44b3bb..aaea00e037 100644 --- a/eth/handler.go +++ b/eth/handler.go @@ -352,6 +352,8 @@ func (h *handler) runEthPeer(peer *eth.Peer, handler eth.Handler) error { case <-timeout.C: peer.Log().Warn("Required block challenge timed out, dropping", "addr", peer.RemoteAddr(), "type", peer.Name()) h.removePeer(peer.ID()) + case <-dead: + // Peer handler terminated, abort all goroutines } }(number, hash, req) } From a4d3fb98059fc0c0fc13bdb04d3788f691829b2c Mon Sep 17 00:00:00 2001 From: cui Date: Wed, 13 Aug 2025 15:08:23 +0800 Subject: [PATCH 42/57] node: remove unused err var (#32398) --- node/errors.go | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/node/errors.go b/node/errors.go index 67547bf691..f9188f8d99 100644 --- a/node/errors.go +++ b/node/errors.go @@ -24,10 +24,9 @@ import ( ) var ( - ErrDatadirUsed = errors.New("datadir already used by another process") - ErrNodeStopped = errors.New("node not started") - ErrNodeRunning = errors.New("node already running") - ErrServiceUnknown = errors.New("unknown service") + ErrDatadirUsed = errors.New("datadir already used by another process") + ErrNodeStopped = errors.New("node not started") + ErrNodeRunning = errors.New("node already running") datadirInUseErrnos = map[uint]bool{11: true, 32: true, 35: true} ) From f054befc5511de8d252d8fb6ecd847471d4c2c00 Mon Sep 17 00:00:00 2001 From: cui Date: Wed, 13 Aug 2025 18:00:54 +0800 Subject: [PATCH 43/57] rlp: optimize intsize (#32421) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit goos: darwin goarch: arm64 pkg: github.com/ethereum/go-ethereum/rlp cpu: Apple M4 │ old.txt │ new.txt │ │ sec/op │ sec/op vs base │ Intsize 2.175n ± 5% 1.050n ± 4% -51.76% (p=0.000 n=10) --- rlp/encode.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/rlp/encode.go b/rlp/encode.go index 623932a90b..de2b02f629 100644 --- a/rlp/encode.go +++ b/rlp/encode.go @@ -21,6 +21,7 @@ import ( "fmt" "io" "math/big" + "math/bits" "reflect" "github.com/ethereum/go-ethereum/rlp/internal/rlpstruct" @@ -487,9 +488,8 @@ func putint(b []byte, i uint64) (size int) { // intsize computes the minimum number of bytes required to store i. func intsize(i uint64) (size int) { - for size = 1; ; size++ { - if i >>= 8; i == 0 { - return size - } + if i == 0 { + return 1 } + return (bits.Len64(i) + 7) / 8 } From 51342136fadf2972320cd70badb1336efe3259e1 Mon Sep 17 00:00:00 2001 From: Nebojsa Urosevic Date: Wed, 13 Aug 2025 14:51:38 +0300 Subject: [PATCH 44/57] eth/tracers: Adds codeHash to prestateTracer's response (#32391) **Problem:** Including full account code in prestateTracer response significantly increases response payload size. **Solution:** Add codeHash field to the response. This will allow client-side bytecode caching and is a non-breaking change. **Note:** codeHash for EoAs is excluded to save space. --------- Co-authored-by: Sina Mahmoodi --- .../internal/tracetest/calltrace_test.go | 4 +-- .../prestate_tracer/7702_delegate.json | 3 ++ .../prestate_tracer/disable_code.json | 1 + .../disable_code_and_storage.json | 3 +- .../prestate_tracer/disable_storage.json | 3 +- .../testdata/prestate_tracer/setcode_tx.json | 3 +- .../testdata/prestate_tracer/simple.json | 1 + .../create.json | 1 + .../create_disable_code.json | 1 + .../create_disable_storage.json | 3 +- .../create_post_eip158.json | 3 +- .../inner_create.json | 6 +++- ...inner_create_disable_code_and_storage.json | 12 +++++--- .../simple.json | 1 + .../simple_disable_code_and_storage.json | 1 + .../suicide.json | 1 + eth/tracers/native/gen_account_json.go | 22 +++++++++----- eth/tracers/native/prestate.go | 30 +++++++++++++++---- 18 files changed, 74 insertions(+), 25 deletions(-) diff --git a/eth/tracers/internal/tracetest/calltrace_test.go b/eth/tracers/internal/tracetest/calltrace_test.go index 70da34f427..b454522978 100644 --- a/eth/tracers/internal/tracetest/calltrace_test.go +++ b/eth/tracers/internal/tracetest/calltrace_test.go @@ -321,7 +321,7 @@ func TestInternals(t *testing.T) { byte(vm.LOG0), }, tracer: mkTracer("prestateTracer", nil), - want: fmt.Sprintf(`{"0x00000000000000000000000000000000deadbeef":{"balance":"0x0","code":"0x6001600052600164ffffffffff60016000f560ff6000a0"},"%s":{"balance":"0x1c6bf52634000"}}`, originHex), + want: fmt.Sprintf(`{"0x00000000000000000000000000000000deadbeef":{"balance":"0x0","code":"0x6001600052600164ffffffffff60016000f560ff6000a0","codeHash":"0x27be17a236425a9b513d736c4bb84eca4505a15564cae640e85558cf4d7ff7bb"},"%s":{"balance":"0x1c6bf52634000"}}`, originHex), }, { // CREATE2 which requires padding memory by prestate tracer @@ -340,7 +340,7 @@ func TestInternals(t *testing.T) { byte(vm.LOG0), }, tracer: mkTracer("prestateTracer", nil), - want: fmt.Sprintf(`{"0x00000000000000000000000000000000deadbeef":{"balance":"0x0","code":"0x6001600052600160ff60016000f560ff6000a0"},"%s":{"balance":"0x1c6bf52634000"}}`, originHex), + want: fmt.Sprintf(`{"0x00000000000000000000000000000000deadbeef":{"balance":"0x0","code":"0x6001600052600160ff60016000f560ff6000a0","codeHash":"0x5544040a7fd107ba8164108904724a38fb9c664daae88a5cc53580841e648edf"},"%s":{"balance":"0x1c6bf52634000"}}`, originHex), }, } { t.Run(tc.name, func(t *testing.T) { diff --git a/eth/tracers/internal/tracetest/testdata/prestate_tracer/7702_delegate.json b/eth/tracers/internal/tracetest/testdata/prestate_tracer/7702_delegate.json index 14874dcc07..ca7e1f35c7 100644 --- a/eth/tracers/internal/tracetest/testdata/prestate_tracer/7702_delegate.json +++ b/eth/tracers/internal/tracetest/testdata/prestate_tracer/7702_delegate.json @@ -115,6 +115,7 @@ "0x17816e9a858b161c3e37016d139cf618056cacd4": { "balance": "0x0", "code": "0xef0100b684710e6d5914ad6e64493de2a3c424cc43e970", + "codeHash":"0xca4cab497827c53a640924e1f7ebb69c3280f8ce8cef2d1d2f9a3707def2a856", "nonce": 15809 }, "0x4838b106fce9647bdf1e7877bf73ce8b0bad5f97": { @@ -124,11 +125,13 @@ "0xb684710e6d5914ad6e64493de2a3c424cc43e970": { "balance": "0x0", "code": "0x60806040525f4711156100b6575f3273ffffffffffffffffffffffffffffffffffffffff16476040516100319061048b565b5f6040518083038185875af1925050503d805f811461006b576040519150601f19603f3d011682016040523d82523d5f602084013e610070565b606091505b50509050806100b4576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016100ab906104f9565b60405180910390fd5b505b73ffffffffffffffffffffffffffffffffffffffff80166001336100da9190610563565b73ffffffffffffffffffffffffffffffffffffffff161115610131576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610128906105f4565b60405180910390fd5b73b9df4a9ba45917e71d664d51462d46926e4798e873ffffffffffffffffffffffffffffffffffffffff166001336101699190610563565b73ffffffffffffffffffffffffffffffffffffffff160361045c575f8036906101929190610631565b5f1c90505f73cda6461f1a30c618373f5790a83e1569fb685cba73ffffffffffffffffffffffffffffffffffffffff16631f3a71ba306040518263ffffffff1660e01b81526004016101e491906106af565b602060405180830381865afa1580156101ff573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061022391906106ff565b90508181106104595773cda6461f1a30c618373f5790a83e1569fb685cba73ffffffffffffffffffffffffffffffffffffffff1663a9059cbb5f836040518363ffffffff1660e01b815260040161027b929190610739565b6020604051808303815f875af1158015610297573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906102bb9190610795565b6102fa576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016102f1906104f9565b60405180910390fd5b5f73236501327e701692a281934230af0b6be8df335373ffffffffffffffffffffffffffffffffffffffff166370a08231306040518263ffffffff1660e01b815260040161034891906106af565b602060405180830381865afa158015610363573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061038791906106ff565b905073236501327e701692a281934230af0b6be8df335373ffffffffffffffffffffffffffffffffffffffff1663a9059cbb32836040518363ffffffff1660e01b81526004016103d8929190610739565b6020604051808303815f875af11580156103f4573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906104189190610795565b610457576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161044e9061080a565b60405180910390fd5b505b50505b005b5f81905092915050565b50565b5f6104765f8361045e565b915061048182610468565b5f82019050919050565b5f6104958261046b565b9150819050919050565b5f82825260208201905092915050565b7f5472616e73666572206661696c656400000000000000000000000000000000005f82015250565b5f6104e3600f8361049f565b91506104ee826104af565b602082019050919050565b5f6020820190508181035f830152610510816104d7565b9050919050565b5f73ffffffffffffffffffffffffffffffffffffffff82169050919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b5f61056d82610517565b915061057883610517565b9250828201905073ffffffffffffffffffffffffffffffffffffffff8111156105a4576105a3610536565b5b92915050565b7f50616e69632831372900000000000000000000000000000000000000000000005f82015250565b5f6105de60098361049f565b91506105e9826105aa565b602082019050919050565b5f6020820190508181035f83015261060b816105d2565b9050919050565b5f82905092915050565b5f819050919050565b5f82821b905092915050565b5f61063c8383610612565b82610647813561061c565b92506020821015610687576106827fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff83602003600802610625565b831692505b505092915050565b5f61069982610517565b9050919050565b6106a98161068f565b82525050565b5f6020820190506106c25f8301846106a0565b92915050565b5f80fd5b5f819050919050565b6106de816106cc565b81146106e8575f80fd5b50565b5f815190506106f9816106d5565b92915050565b5f60208284031215610714576107136106c8565b5b5f610721848285016106eb565b91505092915050565b610733816106cc565b82525050565b5f60408201905061074c5f8301856106a0565b610759602083018461072a565b9392505050565b5f8115159050919050565b61077481610760565b811461077e575f80fd5b50565b5f8151905061078f8161076b565b92915050565b5f602082840312156107aa576107a96106c8565b5b5f6107b784828501610781565b91505092915050565b7f546f6b656e207472616e73666572206661696c656400000000000000000000005f82015250565b5f6107f460158361049f565b91506107ff826107c0565b602082019050919050565b5f6020820190508181035f830152610821816107e8565b905091905056fea2646970667358221220b6a06cc7b930dc4e34352a145f3548d57ec5a60d0097c1979ef363376bf9a69164736f6c63430008140033", + "codeHash":"0x710e40f71ebfefb907b9970505d085952d073dedc9a67e7ce2db450194c9ad04", "nonce": 1 }, "0xb9df4a9ba45917e71d664d51462d46926e4798e7": { "balance": "0x597af049b190a724", "code": "0xef0100000000009b1d0af20d8c6d0a44e162d11f9b8f00", + "codeHash":"0xbb1a21a37f4391e14c4817bca5df4ed60b84e372053b367731ccd8ab0fb6daf1", "nonce": 1887 } } diff --git a/eth/tracers/internal/tracetest/testdata/prestate_tracer/disable_code.json b/eth/tracers/internal/tracetest/testdata/prestate_tracer/disable_code.json index 5601ac797a..d5530ca61d 100644 --- a/eth/tracers/internal/tracetest/testdata/prestate_tracer/disable_code.json +++ b/eth/tracers/internal/tracetest/testdata/prestate_tracer/disable_code.json @@ -65,6 +65,7 @@ "0x3b873a919aa0512d5a0f09e6dcceaa4a6727fafe": { "balance": "0x4d87094125a369d9bd5", "nonce": 1, + "codeHash": "0xec0ba40983fafc34be1bda1b3a3c6eabdd60fa4ce6eab345be1e51bda01d0d4f", "storage": { "0x0000000000000000000000000000000000000000000000000000000000000000": "0x000000000000000000000001b436ba50d378d4bbc8660d312a13df6af6e89dfb", "0x0000000000000000000000000000000000000000000000000000000000000001": "0x00000000000000000000000000000000000000000000000006f05b59d3b20000", diff --git a/eth/tracers/internal/tracetest/testdata/prestate_tracer/disable_code_and_storage.json b/eth/tracers/internal/tracetest/testdata/prestate_tracer/disable_code_and_storage.json index 310a6696b8..9c39eca77b 100644 --- a/eth/tracers/internal/tracetest/testdata/prestate_tracer/disable_code_and_storage.json +++ b/eth/tracers/internal/tracetest/testdata/prestate_tracer/disable_code_and_storage.json @@ -65,7 +65,8 @@ }, "0x3b873a919aa0512d5a0f09e6dcceaa4a6727fafe": { "balance": "0x4d87094125a369d9bd5", - "nonce": 1 + "nonce": 1, + "codeHash": "0xec0ba40983fafc34be1bda1b3a3c6eabdd60fa4ce6eab345be1e51bda01d0d4f" }, "0xb436ba50d378d4bbc8660d312a13df6af6e89dfb": { "balance": "0x1780d77678137ac1b775", diff --git a/eth/tracers/internal/tracetest/testdata/prestate_tracer/disable_storage.json b/eth/tracers/internal/tracetest/testdata/prestate_tracer/disable_storage.json index c0cb05a2a2..a70151650e 100644 --- a/eth/tracers/internal/tracetest/testdata/prestate_tracer/disable_storage.json +++ b/eth/tracers/internal/tracetest/testdata/prestate_tracer/disable_storage.json @@ -65,7 +65,8 @@ "0x3b873a919aa0512d5a0f09e6dcceaa4a6727fafe": { "balance": "0x4d87094125a369d9bd5", "nonce": 1, - "code": "0x606060405236156100935763ffffffff60e060020a60003504166311ee8382811461009c57806313af4035146100be5780631f5e8f4c146100ee57806324daddc5146101125780634921a91a1461013b57806363e4bff414610157578063764978f91461017f578063893d20e8146101a1578063ba40aaa1146101cd578063cebc9a82146101f4578063e177246e14610216575b61009a5b5b565b005b34156100a457fe5b6100ac61023d565b60408051918252519081900360200190f35b34156100c657fe5b6100da600160a060020a0360043516610244565b604080519115158252519081900360200190f35b34156100f657fe5b6100da610307565b604080519115158252519081900360200190f35b341561011a57fe5b6100da6004351515610318565b604080519115158252519081900360200190f35b6100da6103d6565b604080519115158252519081900360200190f35b6100da600160a060020a0360043516610420565b604080519115158252519081900360200190f35b341561018757fe5b6100ac61046c565b60408051918252519081900360200190f35b34156101a957fe5b6101b1610473565b60408051600160a060020a039092168252519081900360200190f35b34156101d557fe5b6100da600435610483565b604080519115158252519081900360200190f35b34156101fc57fe5b6100ac61050d565b60408051918252519081900360200190f35b341561021e57fe5b6100da600435610514565b604080519115158252519081900360200190f35b6003545b90565b60006000610250610473565b600160a060020a031633600160a060020a03161415156102705760006000fd5b600160a060020a03831615156102865760006000fd5b50600054600160a060020a0390811690831681146102fb57604051600160a060020a0380851691908316907ffcf23a92150d56e85e3a3d33b357493246e55783095eb6a733eb8439ffc752c890600090a360008054600160a060020a031916600160a060020a03851617905560019150610300565b600091505b5b50919050565b60005460a060020a900460ff165b90565b60006000610324610473565b600160a060020a031633600160a060020a03161415156103445760006000fd5b5060005460a060020a900460ff16801515831515146102fb576000546040805160a060020a90920460ff1615158252841515602083015280517fe6cd46a119083b86efc6884b970bfa30c1708f53ba57b86716f15b2f4551a9539281900390910190a16000805460a060020a60ff02191660a060020a8515150217905560019150610300565b600091505b5b50919050565b60006103e0610307565b801561040557506103ef610473565b600160a060020a031633600160a060020a031614155b156104105760006000fd5b610419336105a0565b90505b5b90565b600061042a610307565b801561044f5750610439610473565b600160a060020a031633600160a060020a031614155b1561045a5760006000fd5b610463826105a0565b90505b5b919050565b6001545b90565b600054600160a060020a03165b90565b6000600061048f610473565b600160a060020a031633600160a060020a03161415156104af5760006000fd5b506001548281146102fb57604080518281526020810185905281517f79a3746dde45672c9e8ab3644b8bb9c399a103da2dc94b56ba09777330a83509929181900390910190a160018381559150610300565b600091505b5b50919050565b6002545b90565b60006000610520610473565b600160a060020a031633600160a060020a03161415156105405760006000fd5b506002548281146102fb57604080518281526020810185905281517ff6991a728965fedd6e927fdf16bdad42d8995970b4b31b8a2bf88767516e2494929181900390910190a1600283905560019150610300565b600091505b5b50919050565b60006000426105ad61023d565b116102fb576105c46105bd61050d565b4201610652565b6105cc61046c565b604051909150600160a060020a038416908290600081818185876187965a03f1925050501561063d57604080518281529051600160a060020a038516917f9bca65ce52fdef8a470977b51f247a2295123a4807dfa9e502edf0d30722da3b919081900360200190a260019150610300565b6102fb42610652565b5b600091505b50919050565b60038190555b505600a165627a7a72305820f3c973c8b7ed1f62000b6701bd5b708469e19d0f1d73fde378a56c07fd0b19090029" + "code": "0x606060405236156100935763ffffffff60e060020a60003504166311ee8382811461009c57806313af4035146100be5780631f5e8f4c146100ee57806324daddc5146101125780634921a91a1461013b57806363e4bff414610157578063764978f91461017f578063893d20e8146101a1578063ba40aaa1146101cd578063cebc9a82146101f4578063e177246e14610216575b61009a5b5b565b005b34156100a457fe5b6100ac61023d565b60408051918252519081900360200190f35b34156100c657fe5b6100da600160a060020a0360043516610244565b604080519115158252519081900360200190f35b34156100f657fe5b6100da610307565b604080519115158252519081900360200190f35b341561011a57fe5b6100da6004351515610318565b604080519115158252519081900360200190f35b6100da6103d6565b604080519115158252519081900360200190f35b6100da600160a060020a0360043516610420565b604080519115158252519081900360200190f35b341561018757fe5b6100ac61046c565b60408051918252519081900360200190f35b34156101a957fe5b6101b1610473565b60408051600160a060020a039092168252519081900360200190f35b34156101d557fe5b6100da600435610483565b604080519115158252519081900360200190f35b34156101fc57fe5b6100ac61050d565b60408051918252519081900360200190f35b341561021e57fe5b6100da600435610514565b604080519115158252519081900360200190f35b6003545b90565b60006000610250610473565b600160a060020a031633600160a060020a03161415156102705760006000fd5b600160a060020a03831615156102865760006000fd5b50600054600160a060020a0390811690831681146102fb57604051600160a060020a0380851691908316907ffcf23a92150d56e85e3a3d33b357493246e55783095eb6a733eb8439ffc752c890600090a360008054600160a060020a031916600160a060020a03851617905560019150610300565b600091505b5b50919050565b60005460a060020a900460ff165b90565b60006000610324610473565b600160a060020a031633600160a060020a03161415156103445760006000fd5b5060005460a060020a900460ff16801515831515146102fb576000546040805160a060020a90920460ff1615158252841515602083015280517fe6cd46a119083b86efc6884b970bfa30c1708f53ba57b86716f15b2f4551a9539281900390910190a16000805460a060020a60ff02191660a060020a8515150217905560019150610300565b600091505b5b50919050565b60006103e0610307565b801561040557506103ef610473565b600160a060020a031633600160a060020a031614155b156104105760006000fd5b610419336105a0565b90505b5b90565b600061042a610307565b801561044f5750610439610473565b600160a060020a031633600160a060020a031614155b1561045a5760006000fd5b610463826105a0565b90505b5b919050565b6001545b90565b600054600160a060020a03165b90565b6000600061048f610473565b600160a060020a031633600160a060020a03161415156104af5760006000fd5b506001548281146102fb57604080518281526020810185905281517f79a3746dde45672c9e8ab3644b8bb9c399a103da2dc94b56ba09777330a83509929181900390910190a160018381559150610300565b600091505b5b50919050565b6002545b90565b60006000610520610473565b600160a060020a031633600160a060020a03161415156105405760006000fd5b506002548281146102fb57604080518281526020810185905281517ff6991a728965fedd6e927fdf16bdad42d8995970b4b31b8a2bf88767516e2494929181900390910190a1600283905560019150610300565b600091505b5b50919050565b60006000426105ad61023d565b116102fb576105c46105bd61050d565b4201610652565b6105cc61046c565b604051909150600160a060020a038416908290600081818185876187965a03f1925050501561063d57604080518281529051600160a060020a038516917f9bca65ce52fdef8a470977b51f247a2295123a4807dfa9e502edf0d30722da3b919081900360200190a260019150610300565b6102fb42610652565b5b600091505b50919050565b60038190555b505600a165627a7a72305820f3c973c8b7ed1f62000b6701bd5b708469e19d0f1d73fde378a56c07fd0b19090029", + "codeHash": "0xec0ba40983fafc34be1bda1b3a3c6eabdd60fa4ce6eab345be1e51bda01d0d4f" }, "0xb436ba50d378d4bbc8660d312a13df6af6e89dfb": { "balance": "0x1780d77678137ac1b775", diff --git a/eth/tracers/internal/tracetest/testdata/prestate_tracer/setcode_tx.json b/eth/tracers/internal/tracetest/testdata/prestate_tracer/setcode_tx.json index 121509f132..03e825fe2f 100644 --- a/eth/tracers/internal/tracetest/testdata/prestate_tracer/setcode_tx.json +++ b/eth/tracers/internal/tracetest/testdata/prestate_tracer/setcode_tx.json @@ -83,7 +83,8 @@ }, "0x000000000000000000000000000000000000bbbb": { "balance": "0x0", - "code": "0x6042604255" + "code": "0x6042604255", + "codeHash":"0xfa2f0a459fb0004c3c79afe1ab7612a23f1e649b3b352242f8c7c45a0e3585b6" }, "0x703c4b2bd70c169f5717101caee543299fc946c7": { "balance": "0xde0b6b3a7640000", diff --git a/eth/tracers/internal/tracetest/testdata/prestate_tracer/simple.json b/eth/tracers/internal/tracetest/testdata/prestate_tracer/simple.json index bbfdae306e..bd57764e6b 100644 --- a/eth/tracers/internal/tracetest/testdata/prestate_tracer/simple.json +++ b/eth/tracers/internal/tracetest/testdata/prestate_tracer/simple.json @@ -64,6 +64,7 @@ "balance": "0x4d87094125a369d9bd5", "nonce": 1, "code": "0x606060405236156100935763ffffffff60e060020a60003504166311ee8382811461009c57806313af4035146100be5780631f5e8f4c146100ee57806324daddc5146101125780634921a91a1461013b57806363e4bff414610157578063764978f91461017f578063893d20e8146101a1578063ba40aaa1146101cd578063cebc9a82146101f4578063e177246e14610216575b61009a5b5b565b005b34156100a457fe5b6100ac61023d565b60408051918252519081900360200190f35b34156100c657fe5b6100da600160a060020a0360043516610244565b604080519115158252519081900360200190f35b34156100f657fe5b6100da610307565b604080519115158252519081900360200190f35b341561011a57fe5b6100da6004351515610318565b604080519115158252519081900360200190f35b6100da6103d6565b604080519115158252519081900360200190f35b6100da600160a060020a0360043516610420565b604080519115158252519081900360200190f35b341561018757fe5b6100ac61046c565b60408051918252519081900360200190f35b34156101a957fe5b6101b1610473565b60408051600160a060020a039092168252519081900360200190f35b34156101d557fe5b6100da600435610483565b604080519115158252519081900360200190f35b34156101fc57fe5b6100ac61050d565b60408051918252519081900360200190f35b341561021e57fe5b6100da600435610514565b604080519115158252519081900360200190f35b6003545b90565b60006000610250610473565b600160a060020a031633600160a060020a03161415156102705760006000fd5b600160a060020a03831615156102865760006000fd5b50600054600160a060020a0390811690831681146102fb57604051600160a060020a0380851691908316907ffcf23a92150d56e85e3a3d33b357493246e55783095eb6a733eb8439ffc752c890600090a360008054600160a060020a031916600160a060020a03851617905560019150610300565b600091505b5b50919050565b60005460a060020a900460ff165b90565b60006000610324610473565b600160a060020a031633600160a060020a03161415156103445760006000fd5b5060005460a060020a900460ff16801515831515146102fb576000546040805160a060020a90920460ff1615158252841515602083015280517fe6cd46a119083b86efc6884b970bfa30c1708f53ba57b86716f15b2f4551a9539281900390910190a16000805460a060020a60ff02191660a060020a8515150217905560019150610300565b600091505b5b50919050565b60006103e0610307565b801561040557506103ef610473565b600160a060020a031633600160a060020a031614155b156104105760006000fd5b610419336105a0565b90505b5b90565b600061042a610307565b801561044f5750610439610473565b600160a060020a031633600160a060020a031614155b1561045a5760006000fd5b610463826105a0565b90505b5b919050565b6001545b90565b600054600160a060020a03165b90565b6000600061048f610473565b600160a060020a031633600160a060020a03161415156104af5760006000fd5b506001548281146102fb57604080518281526020810185905281517f79a3746dde45672c9e8ab3644b8bb9c399a103da2dc94b56ba09777330a83509929181900390910190a160018381559150610300565b600091505b5b50919050565b6002545b90565b60006000610520610473565b600160a060020a031633600160a060020a03161415156105405760006000fd5b506002548281146102fb57604080518281526020810185905281517ff6991a728965fedd6e927fdf16bdad42d8995970b4b31b8a2bf88767516e2494929181900390910190a1600283905560019150610300565b600091505b5b50919050565b60006000426105ad61023d565b116102fb576105c46105bd61050d565b4201610652565b6105cc61046c565b604051909150600160a060020a038416908290600081818185876187965a03f1925050501561063d57604080518281529051600160a060020a038516917f9bca65ce52fdef8a470977b51f247a2295123a4807dfa9e502edf0d30722da3b919081900360200190a260019150610300565b6102fb42610652565b5b600091505b50919050565b60038190555b505600a165627a7a72305820f3c973c8b7ed1f62000b6701bd5b708469e19d0f1d73fde378a56c07fd0b19090029", + "codeHash": "0xec0ba40983fafc34be1bda1b3a3c6eabdd60fa4ce6eab345be1e51bda01d0d4f", "storage": { "0x0000000000000000000000000000000000000000000000000000000000000000": "0x000000000000000000000001b436ba50d378d4bbc8660d312a13df6af6e89dfb", "0x0000000000000000000000000000000000000000000000000000000000000001": "0x00000000000000000000000000000000000000000000000006f05b59d3b20000", diff --git a/eth/tracers/internal/tracetest/testdata/prestate_tracer_with_diff_mode/create.json b/eth/tracers/internal/tracetest/testdata/prestate_tracer_with_diff_mode/create.json index 6eea6085b8..696f3fb04f 100644 --- a/eth/tracers/internal/tracetest/testdata/prestate_tracer_with_diff_mode/create.json +++ b/eth/tracers/internal/tracetest/testdata/prestate_tracer_with_diff_mode/create.json @@ -71,6 +71,7 @@ }, "0x40f2f445da6c9047554683fb382fba6769717116": { "code": "0x60606040526000357c01000000000000000000000000000000000000000000000000000000009004806341c0e1b514610044578063cfae32171461005157610042565b005b61004f6004506100ca565b005b61005c60045061015e565b60405180806020018281038252838181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f1680156100bc5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b600060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16141561015b57600060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16ff5b5b565b60206040519081016040528060008152602001506001600050805480601f016020809104026020016040519081016040528092919081815260200182805480156101cd57820191906000526020600020905b8154815290600101906020018083116101b057829003601f168201915b505050505090506101d9565b9056", + "codeHash": "0x19463d2ef23c9fcb3f853199279ecc9b21fa4147112bfe85664141ffbffd1a37", "storage": { "0x0000000000000000000000000000000000000000000000000000000000000000": "0x000000000000000000000000f0c5cef39b17c213cfe090a46b8c7760ffb7928a", "0x0000000000000000000000000000000000000000000000000000000000000001": "0x00000000000000000000000000000000000000000000000000000000000001ee", diff --git a/eth/tracers/internal/tracetest/testdata/prestate_tracer_with_diff_mode/create_disable_code.json b/eth/tracers/internal/tracetest/testdata/prestate_tracer_with_diff_mode/create_disable_code.json index 5d7c024a5e..81382524ab 100644 --- a/eth/tracers/internal/tracetest/testdata/prestate_tracer_with_diff_mode/create_disable_code.json +++ b/eth/tracers/internal/tracetest/testdata/prestate_tracer_with_diff_mode/create_disable_code.json @@ -70,6 +70,7 @@ "balance": "0x9fb71abdd2621d8886" }, "0x40f2f445da6c9047554683fb382fba6769717116": { + "codeHash":"0x19463d2ef23c9fcb3f853199279ecc9b21fa4147112bfe85664141ffbffd1a37", "storage": { "0x0000000000000000000000000000000000000000000000000000000000000000": "0x000000000000000000000000f0c5cef39b17c213cfe090a46b8c7760ffb7928a", "0x0000000000000000000000000000000000000000000000000000000000000001": "0x00000000000000000000000000000000000000000000000000000000000001ee", diff --git a/eth/tracers/internal/tracetest/testdata/prestate_tracer_with_diff_mode/create_disable_storage.json b/eth/tracers/internal/tracetest/testdata/prestate_tracer_with_diff_mode/create_disable_storage.json index 65594feb44..e36670e50b 100644 --- a/eth/tracers/internal/tracetest/testdata/prestate_tracer_with_diff_mode/create_disable_storage.json +++ b/eth/tracers/internal/tracetest/testdata/prestate_tracer_with_diff_mode/create_disable_storage.json @@ -70,7 +70,8 @@ "balance": "0x9fb71abdd2621d8886" }, "0x40f2f445da6c9047554683fb382fba6769717116": { - "code": "0x60606040526000357c01000000000000000000000000000000000000000000000000000000009004806341c0e1b514610044578063cfae32171461005157610042565b005b61004f6004506100ca565b005b61005c60045061015e565b60405180806020018281038252838181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f1680156100bc5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b600060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16141561015b57600060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16ff5b5b565b60206040519081016040528060008152602001506001600050805480601f016020809104026020016040519081016040528092919081815260200182805480156101cd57820191906000526020600020905b8154815290600101906020018083116101b057829003601f168201915b505050505090506101d9565b9056" + "code": "0x60606040526000357c01000000000000000000000000000000000000000000000000000000009004806341c0e1b514610044578063cfae32171461005157610042565b005b61004f6004506100ca565b005b61005c60045061015e565b60405180806020018281038252838181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f1680156100bc5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b600060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16141561015b57600060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16ff5b5b565b60206040519081016040528060008152602001506001600050805480601f016020809104026020016040519081016040528092919081815260200182805480156101cd57820191906000526020600020905b8154815290600101906020018083116101b057829003601f168201915b505050505090506101d9565b9056", + "codeHash": "0x19463d2ef23c9fcb3f853199279ecc9b21fa4147112bfe85664141ffbffd1a37" }, "0xf0c5cef39b17c213cfe090a46b8c7760ffb7928a": { "balance": "0x15b058920efcc5188", diff --git a/eth/tracers/internal/tracetest/testdata/prestate_tracer_with_diff_mode/create_post_eip158.json b/eth/tracers/internal/tracetest/testdata/prestate_tracer_with_diff_mode/create_post_eip158.json index 19e1f08bb7..26d0572517 100644 --- a/eth/tracers/internal/tracetest/testdata/prestate_tracer_with_diff_mode/create_post_eip158.json +++ b/eth/tracers/internal/tracetest/testdata/prestate_tracer_with_diff_mode/create_post_eip158.json @@ -57,8 +57,9 @@ "result": { "post": { "0x1bda2f8e4735507930bd6cfe873bf0bf0f4ab1de": { + "nonce": 1, "code": "0x608060405234801561001057600080fd5b50600436106100365760003560e01c806309ce9ccb1461003b5780633fb5c1cb14610059575b600080fd5b610043610075565b60405161005091906100e2565b60405180910390f35b610073600480360381019061006e919061012e565b61007b565b005b60005481565b80600081905550600a8111156100c6576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016100bd906101de565b60405180910390fd5b50565b6000819050919050565b6100dc816100c9565b82525050565b60006020820190506100f760008301846100d3565b92915050565b600080fd5b61010b816100c9565b811461011657600080fd5b50565b60008135905061012881610102565b92915050565b600060208284031215610144576101436100fd565b5b600061015284828501610119565b91505092915050565b600082825260208201905092915050565b7f4e756d6265722069732067726561746572207468616e2031302c207472616e7360008201527f616374696f6e2072657665727465642e00000000000000000000000000000000602082015250565b60006101c860308361015b565b91506101d38261016c565b604082019050919050565b600060208201905081810360008301526101f7816101bb565b905091905056fea264697066735822122069018995fecf03bda91a88b6eafe41641709dee8b4a706fe301c8a569fe8c1b364736f6c63430008130033", - "nonce": 1 + "codeHash": "0xf6387add93966c115d42eb1ecd36a1fa28841703312943db753b88f890cc1666" }, "0x2445e8c26a2bf3d1e59f1bb9b1d442caf90768e0": { "balance": "0x10f0645688331eb5690" diff --git a/eth/tracers/internal/tracetest/testdata/prestate_tracer_with_diff_mode/inner_create.json b/eth/tracers/internal/tracetest/testdata/prestate_tracer_with_diff_mode/inner_create.json index e6d6f2435b..64a7188061 100644 --- a/eth/tracers/internal/tracetest/testdata/prestate_tracer_with_diff_mode/inner_create.json +++ b/eth/tracers/internal/tracetest/testdata/prestate_tracer_with_diff_mode/inner_create.json @@ -212,6 +212,7 @@ "balance": "0x0", "nonce": 237, "code": "0x6060604052361561027c5760e060020a600035046301991313811461027e57806303d22885146102ca5780630450991814610323578063049ae734146103705780630ce46c43146103c35780630e85023914610602578063112e39a8146106755780631b4fa6ab146106c25780631e74a2d3146106d057806326a7985a146106fd5780633017fe2414610753578063346cabbc1461075c578063373a1bc3146107d55780633a9e74331461081e5780633c2c21a01461086e5780633d9ce89b146108ba578063480b70bd1461092f578063481078431461097e57806348f0518714610a0e5780634c471cde14610a865780634db3da8314610b09578063523ccfa814610b4f578063586a69fa14610be05780635a9f2def14610c3657806364ee49fe14610caf57806367beaccb14610d055780636840246014610d74578063795b9a6f14610dca5780637b55c8b514610e415780637c73f84614610ee15780638c0e156d14610f145780638c1d01c814610f605780638e46afa914610f69578063938c430714610fc0578063971c803f146111555780639772c982146111ac57806398c9cdf41461122857806398e00e541461127f5780639f927be7146112d5578063a00aede914611383578063a1c0539d146113d3578063aff21c6514611449578063b152f19e14611474578063b549793d146114cb578063b5b33eda1461154b578063bbc6eb1f1461159b578063c0f68859146115ab578063c3a2c0c314611601578063c43d05751461164b578063d8e5c04814611694578063dbfef71014611228578063e29fb547146116e7578063e6470fbe1461173a578063ea27a8811461174c578063ee77fe86146117d1578063f158458c14611851575b005b611882600435602435604435600073e54d323f9ef17c1f0dede47ecc86a9718fe5ea346350d4e41160016000503387876020604051908101604052806000815260200150612225610f6d565b61188260043560243560443560643560843560a43560c435600073e54d323f9ef17c1f0dede47ecc86a9718fe5ea346350d4e4116001600050338b8a6020604051908101604052806000815260200150896125196106c6565b611882600435600073e54d323f9ef17c1f0dede47ecc86a9718fe5ea346350d4e41160016000503385600060e060020a026020604051908101604052806000815260200150611e4a610f6d565b611882600435602435604435606435608435600073e54d323f9ef17c1f0dede47ecc86a9718fe5ea346350d4e41160016000503389896020604051908101604052806000815260200150886124e86106c6565b604080516020604435600481810135601f8101849004840285018401909552848452611882948135946024803595939460649492939101918190840183828082843750506040805160a08082019092529597963596608435969095506101449450925060a491506005908390839080828437509095505050505050604080518082018252600160a060020a03338116825288166020820152815160c0810190925260009173e54d323f9ef17c1f0dede47ecc86a9718fe5ea349163e3042c0f91600191908a908a9089908b90808b8b9090602002015181526020018b60016005811015610002579090602002015181526020018b60026005811015610002579090602002015181526020018b60036005811015610002579090602002015181526020018b6004600581101561000257909060200201518152602001348152602001506040518860e060020a02815260040180888152602001876002602002808383829060006004602084601f0104600f02600301f150905001868152602001806020018560ff1681526020018461ffff168152602001836006602002808383829060006004602084601f0104600f02600301f1509050018281038252868181518152602001915080519060200190808383829060006004602084601f0104600f02600301f150905090810190601f1680156105d25780820380516001836020036101000a031916815260200191505b509850505050505050505060206040518083038160008760325a03f2156100025750506040515191506124cd9050565b60408051602060248035600481810135601f81018590048502860185019096528585526118829581359591946044949293909201918190840183828082843750949650505050505050600073e54d323f9ef17c1f0dede47ecc86a9718fe5ea346350d4e411600133808787611e64610f6d565b611882600435600073e54d323f9ef17c1f0dede47ecc86a9718fe5ea346350d4e41160016000503333600060e060020a026020604051908101604052806000815260200150611d28610f6d565b61189f5b6000611bf8611159565b6118b7600073e54d323f9ef17c1f0dede47ecc86a9718fe5ea3463ea27a881600060005054611a9561159f565b6118b7600073e54d323f9ef17c1f0dede47ecc86a9718fe5ea346326a7985a6040518160e060020a02815260040180905060206040518083038160008760325a03f2156100025750506040515191506107599050565b6118b760075b90565b604080516020606435600481810135601f8101849004840285018401909552848452611882948135946024803595604435956084949201919081908401838280828437509496505093359350505050600073e54d323f9ef17c1f0dede47ecc86a9718fe5ea346350d4e41160013389898861224b610f6d565b611882600435602435600073e54d323f9ef17c1f0dede47ecc86a9718fe5ea346350d4e41160016000503386866020604051908101604052806000815260200150611e64610f6d565b611882600435602435604435606435600073e54d323f9ef17c1f0dede47ecc86a9718fe5ea346350d4e41160016000503333896020604051908101604052806000815260200150886123bc6106c6565b611882600435602435604435600073e54d323f9ef17c1f0dede47ecc86a9718fe5ea346350d4e41160016000503387866020604051908101604052806000815260200150611f8d610f6d565b60408051602060248035600481810135601f810185900485028601850190965285855261188295813595919460449492939092019181908401838280828437509496505093359350505050600073e54d323f9ef17c1f0dede47ecc86a9718fe5ea346350d4e411600133808888612225610f6d565b611882600435602435604435606435600073e54d323f9ef17c1f0dede47ecc86a9718fe5ea346350d4e41160016000503388886020604051908101604052806000815260200150612388610f6d565b611882600435604080517fc4144b2600000000000000000000000000000000000000000000000000000000815260016004820152600160a060020a03831660248201529051600091737c1eb207c07e7ab13cf245585bd03d0fa478d0349163c4144b26916044818101926020929091908290030181878760325a03f215610002575050604051519150611b409050565b604080516020604435600481810135601f81018490048402850184019095528484526118829481359460248035959394606494929391019181908401838280828437509496505093359350505050600073e54d323f9ef17c1f0dede47ecc86a9718fe5ea346350d4e411600133888888612238610f6d565b604080516020604435600481810135601f810184900484028501840190955284845261188294813594602480359593946064949293910191819084018382808284375094965050933593505060843591505060a43560c435600073e54d323f9ef17c1f0dede47ecc86a9718fe5ea346350d4e4116001338b8b8b896126536106c6565b611882600435600073e54d323f9ef17c1f0dede47ecc86a9718fe5ea346350d4e41160016000503333866020604051908101604052806000815260200150611e4a610f6d565b6118b76004355b604080517fed5bd7ea00000000000000000000000000000000000000000000000000000000815260016004820152600160a060020a03831660248201529051600091737c1eb207c07e7ab13cf245585bd03d0fa478d0349163ed5bd7ea916044818101926020929091908290030181878760325a03f215610002575050604051519150611b409050565b61189f600073e54d323f9ef17c1f0dede47ecc86a9718fe5ea3463586a69fa6040518160e060020a02815260040180905060206040518083038160008760325a03f2156100025750506040515191506107599050565b60408051602060248035600481810135601f81018590048502860185019096528585526118829581359591946044949293909201918190840183828082843750949650509335935050606435915050600073e54d323f9ef17c1f0dede47ecc86a9718fe5ea346350d4e411600133808989612388610f6d565b61188260043560243560443560643560843560a435600073e54d323f9ef17c1f0dede47ecc86a9718fe5ea346350d4e4116001600050338a896020604051908101604052806000815260200150886124d76106c6565b6040805160206004803580820135601f8101849004840285018401909552848452611882949193602493909291840191908190840183828082843750949650505050505050600073e54d323f9ef17c1f0dede47ecc86a9718fe5ea346350d4e411600133808587611e4a610f6d565b61188260043560243560443560643560843560a435600073e54d323f9ef17c1f0dede47ecc86a9718fe5ea346350d4e4116001600050338a8a60206040519081016040528060008152602001508961262d6106c6565b604080516020606435600481810135601f810184900484028501840190955284845261188294813594602480359560443595608494920191908190840183828082843750949650505050505050600073e54d323f9ef17c1f0dede47ecc86a9718fe5ea346350d4e4116001338888876120c7610f6d565b604080516020604435600481810135601f81018490048402850184019095528484526118829481359460248035959394606494929391019181908401838280828437505060408051608080820190925295979635969561010495509350608492508591508390839080828437509095505050505050600073e54d323f9ef17c1f0dede47ecc86a9718fe5ea346350d4e4116001338989898961263a6106c6565b6118b7600435602435604435600073e54d323f9ef17c1f0dede47ecc86a9718fe5ea3463ea27a881858585611ba361122c565b611882600435602435604435600073e54d323f9ef17c1f0dede47ecc86a9718fe5ea346350d4e4116001600050333388602060405190810160405280600081526020015061236e610f6d565b6118b760005481565b6118c95b600073e54d323f9ef17c1f0dede47ecc86a9718fe5ea34638e46afa96040518160e060020a02815260040180905060206040518083038160008760325a03f2156100025750506040515191506107599050565b60408051602060248035600481810135601f8101859004850286018501909652858552611882958135959194604494929390920191819084018382808284375094965050933593505060643591505060843560a43560c43560e43561010435600073e54d323f9ef17c1f0dede47ecc86a9718fe5ea346350d4e411600160005033338e8e8d8f8e8e8e8e8e346040518e60e060020a028152600401808e81526020018d600160a060020a031681526020018c600160a060020a031681526020018b8152602001806020018a60ff1681526020018961ffff16815260200188815260200187815260200186815260200185815260200184815260200183815260200182810382528b8181518152602001915080519060200190808383829060006004602084601f0104600f02600301f150905090810190601f1680156111195780820380516001836020036101000a031916815260200191505b509e50505050505050505050505050505060206040518083038160008760325a03f215610002575050604051519b9a5050505050505050505050565b61189f5b600073e54d323f9ef17c1f0dede47ecc86a9718fe5ea3463971c803f6040518160e060020a02815260040180905060206040518083038160008760325a03f2156100025750506040515191506107599050565b604080516020604435600481810135601f8101849004840285018401909552848452611882948135946024803595939460649492939101918190840183828082843750949650509335935050608435915050600073e54d323f9ef17c1f0dede47ecc86a9718fe5ea346350d4e4116001338989896123a2610f6d565b6118b75b600073e54d323f9ef17c1f0dede47ecc86a9718fe5ea346398c9cdf46040518160e060020a02815260040180905060206040518083038160008760325a03f2156100025750506040515191506107599050565b6118b7600073e54d323f9ef17c1f0dede47ecc86a9718fe5ea346398e00e546040518160e060020a02815260040180905060206040518083038160008760325a03f2156100025750506040515191506107599050565b611882600435604080517fe6ce3a6a000000000000000000000000000000000000000000000000000000008152600160048201527f3e3d0000000000000000000000000000000000000000000000000000000000006024820152604481018390529051600091737c1eb207c07e7ab13cf245585bd03d0fa478d0349163e6ce3a6a916064818101926020929091908290030181878760325a03f215610002575050604051519150611b409050565b611882600435602435600073e54d323f9ef17c1f0dede47ecc86a9718fe5ea346350d4e41160016000503385600060e060020a0260206040519081016040528060008152602001506121ef610f6d565b604080516020604435600481810135601f8101849004840285018401909552848452611882948135946024803595939460649492939101918190840183828082843750949650505050505050600073e54d323f9ef17c1f0dede47ecc86a9718fe5ea346350d4e4116001338787876120b5610f6d565b6118b7600435600073e54d323f9ef17c1f0dede47ecc86a9718fe5ea3463ea27a88183611b4561159f565b6118b75b600073e54d323f9ef17c1f0dede47ecc86a9718fe5ea3463b152f19e6040518160e060020a02815260040180905060206040518083038160008760325a03f2156100025750506040515191506107599050565b60408051602060248035600481810135601f8101859004850286018501909652858552611882958135959194604494929390920191819084018382808284375094965050933593505060643591505060843560a435600073e54d323f9ef17c1f0dede47ecc86a9718fe5ea346350d4e411600133808b8b8961262d6106c6565b611882600435602435600073e54d323f9ef17c1f0dede47ecc86a9718fe5ea346350d4e41160016000503386600060e060020a026020604051908101604052806000815260200150612200610f6d565b6118b75b60005460649004610759565b6118b7600073e54d323f9ef17c1f0dede47ecc86a9718fe5ea3463c0f688596040518160e060020a02815260040180905060206040518083038160008760325a03f2156100025750506040515191506107599050565b611882600073e54d323f9ef17c1f0dede47ecc86a9718fe5ea346350d4e41160016000503333600060e060020a026020604051908101604052806000815260200150611bff610f6d565b611882600435602435600073e54d323f9ef17c1f0dede47ecc86a9718fe5ea346350d4e41160016000503333876020604051908101604052806000815260200150612200610f6d565b611882600435602435604435600073e54d323f9ef17c1f0dede47ecc86a9718fe5ea346350d4e41160016000503387600060e060020a026020604051908101604052806000815260200150612213610f6d565b611882600435602435604435606435608435600073e54d323f9ef17c1f0dede47ecc86a9718fe5ea346350d4e411600160005033338a60206040519081016040528060008152602001508961250c6106c6565b61027c6000600060006118e033610b56565b6118b7600435602435604435606435600073e54d323f9ef17c1f0dede47ecc86a9718fe5ea3463ea27a881868686866040518560e060020a0281526004018085815260200184815260200183815260200182815260200194505050505060206040518083038160008760325a03f215610002575050604051519150505b949350505050565b604080516020604435600481810135601f810184900484028501840190955284845261188294813594602480359593946064949293910191819084018382808284375094965050933593505060843591505060a435600073e54d323f9ef17c1f0dede47ecc86a9718fe5ea346350d4e4116001338a8a8a886124fa6106c6565b6118b7600435602435600073e54d323f9ef17c1f0dede47ecc86a9718fe5ea3463ea27a88184846000611b4f61122c565b60408051600160a060020a03929092168252519081900360200190f35b6040805161ffff929092168252519081900360200190f35b60408051918252519081900360200190f35b6040805160ff929092168252519081900360200190f35b15611a905733925082600160a060020a031663c6502da86040518160e060020a0281526004018090506020604051808303816000876161da5a03f1156100025750506040805180517fc6803622000000000000000000000000000000000000000000000000000000008252915191945063c680362291600482810192602092919082900301816000876161da5a03f11561000257505060405151905080156119d1575082600160a060020a031663d379be236040518160e060020a0281526004018090506020604051808303816000876161da5a03f11561000257505060405151600160a060020a03166000141590505b80156119dd5750600082115b80156119ec5750600054600190115b15611a90578183600160a060020a031663830953ab6040518160e060020a0281526004018090506020604051808303816000876161da5a03f1156100025750506040515160640291909104915050604281118015611a4d5750600054829011155b15611a675760008054612710612711909102049055611a90565b602181108015611a7a5750600054829010155b15611a90576000805461271061270f9091020490555b505050565b6000611a9f61122c565b6040518560e060020a0281526004018085815260200184815260200183815260200182815260200194505050505060206040518083038160008760325a03f2156100025750506040515191506107599050565b6040518560e060020a0281526004018085815260200184815260200183815260200182815260200194505050505060206040518083038160008760325a03f215610002575050604051519150505b919050565b6000611af261122c565b6040518560e060020a0281526004018085815260200184815260200183815260200182815260200194505050505060206040518083038160008760325a03f215610002575050604051519150505b92915050565b6040518560e060020a0281526004018085815260200184815260200183815260200182815260200194505050505060206040518083038160008760325a03f215610002575050604051519150505b9392505050565b9050610759565b611c076106c6565b6000611c11611478565b611c1961122c565b600054611c2461159f565b346040518e60e060020a028152600401808e81526020018d600160a060020a031681526020018c600160a060020a031681526020018b8152602001806020018a60ff1681526020018961ffff16815260200188815260200187815260200186815260200185815260200184815260200183815260200182810382528b8181518152602001915080519060200190808383829060006004602084601f0104600f02600301f150905090810190601f168015611cf25780820380516001836020036101000a031916815260200191505b509e50505050505050505050505050505060206040518083038160008760325a03f2156100025750506040515191506107599050565b611d306106c6565b60008b611d3b61122c565b600054611d4661159f565b346040518e60e060020a028152600401808e81526020018d600160a060020a031681526020018c600160a060020a031681526020018b8152602001806020018a60ff1681526020018961ffff16815260200188815260200187815260200186815260200185815260200184815260200183815260200182810382528b8181518152602001915080519060200190808383829060006004602084601f0104600f02600301f150905090810190601f168015611e145780820380516001836020036101000a031916815260200191505b509e50505050505050505050505050505060206040518083038160008760325a03f215610002575050604051519150611b409050565b611e526106c6565b6000611e5c611478565b611d3b61122c565b611e6c6106c6565b6000611e76611478565b611e7e61122c565b600054611e8961159f565b346040518e60e060020a028152600401808e81526020018d600160a060020a031681526020018c600160a060020a031681526020018b8152602001806020018a60ff1681526020018961ffff16815260200188815260200187815260200186815260200185815260200184815260200183815260200182810382528b8181518152602001915080519060200190808383829060006004602084601f0104600f02600301f150905090810190601f168015611f575780820380516001836020036101000a031916815260200191505b509e50505050505050505050505050505060206040518083038160008760325a03f215610002575050604051519150611b9d9050565b611f956106c6565b8b611f9e611478565b611fa661122c565b600054611fb161159f565b346040518e60e060020a028152600401808e81526020018d600160a060020a031681526020018c600160a060020a031681526020018b8152602001806020018a60ff1681526020018961ffff16815260200188815260200187815260200186815260200185815260200184815260200183815260200182810382528b8181518152602001915080519060200190808383829060006004602084601f0104600f02600301f150905090810190601f16801561207f5780820380516001836020036101000a031916815260200191505b509e50505050505050505050505050505060206040518083038160008760325a03f215610002575050604051519150611bf19050565b6120bd6106c6565b6000611f9e611478565b6120cf6106c6565b8b6120d8611478565b6120e061122c565b6000546120eb61159f565b346040518e60e060020a028152600401808e81526020018d600160a060020a031681526020018c600160a060020a031681526020018b8152602001806020018a60ff1681526020018961ffff16815260200188815260200187815260200186815260200185815260200184815260200183815260200182810382528b8181518152602001915080519060200190808383829060006004602084601f0104600f02600301f150905090810190601f1680156121b95780820380516001836020036101000a031916815260200191505b509e50505050505050505050505050505060206040518083038160008760325a03f2156100025750506040515191506117c99050565b6121f76106c6565b8b611e76611478565b6122086106c6565b60008b611e7e61122c565b61221b6106c6565b8a8c611fa661122c565b61222d6106c6565b60008b611fa661122c565b6122406106c6565b60008b6120e061122c565b6122536106c6565b8c8b61225d61122c565b60005461226861159f565b346040518e60e060020a028152600401808e81526020018d600160a060020a031681526020018c600160a060020a031681526020018b8152602001806020018a60ff1681526020018961ffff16815260200188815260200187815260200186815260200185815260200184815260200183815260200182810382528b8181518152602001915080519060200190808383829060006004602084601f0104600f02600301f150905090810190601f1680156123365780820380516001836020036101000a031916815260200191505b509e50505050505050505050505050505060206040518083038160008760325a03f21561000257505060405151979650505050505050565b6123766106c6565b60008c8c600060005054611fb161159f565b6123906106c6565b60008c8c6000600050546120eb61159f565b6123aa6106c6565b60008c8c60006000505461226861159f565b60008d8d6000600050546120eb61159f565b346040518e60e060020a028152600401808e81526020018d600160a060020a031681526020018c600160a060020a031681526020018b8152602001806020018a60ff1681526020018961ffff16815260200188815260200187815260200186815260200185815260200184815260200183815260200182810382528b8181518152602001915080519060200190808383829060006004602084601f0104600f02600301f150905090810190601f16801561249c5780820380516001836020036101000a031916815260200191505b509e50505050505050505050505050505060206040518083038160008760325a03f215610002575050604051519150505b9695505050505050565b8e8d8d6000600050546123ce61159f565b60008d8d60006000505461226861159f565b60008d8d6000600050546123ce61159f565b60008e8e8d61226861159f565b8f8e8e8d61252561159f565b346040518e60e060020a028152600401808e81526020018d600160a060020a031681526020018c600160a060020a031681526020018b8152602001806020018a60ff1681526020018961ffff16815260200188815260200187815260200186815260200185815260200184815260200183815260200182810382528b8181518152602001915080519060200190808383829060006004602084601f0104600f02600301f150905090810190601f1680156125f35780820380516001836020036101000a031916815260200191505b509e50505050505050505050505050505060206040518083038160008760325a03f215610002575050604051519998505050505050505050565b60008e8e8d6123ce61159f565b8a5160208c015160408d015160608e015161226861159f565b60008e8e8d61252561159f56", + "codeHash": "0x461e17b7ae561793f22843985fc6866a3395c1fcee8ebf2d7ed5f293aec1b473", "storage": { "0x26cba0705aade77fa0f9275b68d01fb71206a44abd3a4f5a838f7241efbc8abf": "0x00000000000000000000000042e69cd0a17ae9992f9ad93d136c4bb0d95e3230", "0x49f03a2c2f4fd666a32141fb324283b6f84a1d07b5fa435669fdb55766aef715": "0x000000000000000000000000d7b0e93fa8386b17fb5d1cf934076203dcc122f3", @@ -226,11 +227,13 @@ }, "0x741467b251fca923d6229c4b439078b55dca233b": { "balance": "0x29c613529e8218f8", - "code": "0x606060405236156101a05760e060020a60003504630924120081146101c25780630a16697a146101cf5780630fd1f94e146101d8578063137c638b1461022e57806321835af61461023b57806324032866146102545780632f95b833146102d65780633017fe24146102e55780633233c686146102ef57806337f4c00e146102fa5780634500054f146103055780634e417a98146103785780634e71d92d146103e15780634f059a43146103f35780636146195414610451578063625cc4651461046157806367ce940d1461046a5780637d298ee314610477578063830953ab146104f9578063938b5f321461050457806395ee122114610516578063974654f41461052a578063a06db7dc14610535578063a9d2293d14610541578063ae45850b14610597578063b0f07e44146105a9578063c19d93fb146105cb578063c6502da81461062e578063c680362214610637578063ca94692d1461064a578063cc3471af14610673578063d379be23146106c9578063d62457f6146106e3578063ea8a1af0146106ee578063f5562753146107f3578063f6b4dfb414610854575b610868600080548190600160a060020a03908116339091161461087a57610994565b610868600b5460ff165b90565b610868600d5481565b6108686000731deeda36e15ec9e80f3d7414d67a4803ae45fc80630fd1f94e6040518160e060020a02815260040180905060206040518083038160008760325a03f2156100025750506040515191506101cc9050565b6108685b62012cc86101cc565b61086860043560008160001415610dc65750600161084f565b6108686004356024356000731deeda36e15ec9e80f3d7414d67a4803ae45fc80630bd295e6600360005085856040518460e060020a0281526004018084815260200183600160a060020a03168152602001828152602001935050505060206040518083038160008760325a03f215610002575050604051519150505b92915050565b61099860085461ffff166101cc565b61086860026101cc565b610868600a546101cc565b6108686006546101cc565b6108686000731deeda36e15ec9e80f3d7414d67a4803ae45fc8063a09431546003600050336040518360e060020a0281526004018083815260200182600160a060020a031681526020019250505060206040518083038160008760325a03f2156100025750506040515191506101cc9050565b6109af60408051602081810183526000825282516004805460026001821615610100026000190190911604601f81018490048402830184019095528482529293909291830182828015610a7d5780601f10610a5257610100808354040283529160200191610a7d565b61086860006000600180610b7b6105cf565b6108686000731deeda36e15ec9e80f3d7414d67a4803ae45fc8063f5562753436040518260e060020a0281526004018082815260200191505060206040518083038160008760325a03f2156100025750506040515191506101cc9050565b610a1d6000600480610c986105cf565b61086860025481565b6108685b620186a06101cc565b6108686004356024355b6000731deeda36e15ec9e80f3d7414d67a4803ae45fc8063a1873db6600360005085856040518460e060020a0281526004018084815260200183600160a060020a03168152602001828152602001935050505060206040518083038160008760325a03f2156100025750506040515191506102d09050565b6108686009546101cc565b610a1f600c54600160a060020a031681565b610868600b5462010000900460ff166101cc565b6108686007546101cc565b610a3c600e5460ff1681565b6108686000731deeda36e15ec9e80f3d7414d67a4803ae45fc8063a9d2293d6040518160e060020a02815260040180905060206040518083038160008760325a03f2156100025750506040515191506101cc9050565b610a1f600054600160a060020a031681565b610868600080548190600160a060020a039081163390911614610a8957610994565b6108685b6000731deeda36e15ec9e80f3d7414d67a4803ae45fc80635054d98a60036000506040518260e060020a0281526004018082815260200191505060206040518083038160008760325a03f2156100025750506040515191506101cc9050565b61086860015481565b610868600b54610100900460ff166101cc565b61086860035474010000000000000000000000000000000000000000900460e060020a026101cc565b6108686000731deeda36e15ec9e80f3d7414d67a4803ae45fc8063cc3471af6040518160e060020a02815260040180905060206040518083038160008760325a03f2156100025750506040515191506101cc9050565b610a1f600854620100009004600160a060020a03166101cc565b6108686005546101cc565b610a1d604080517fa09431540000000000000000000000000000000000000000000000000000000081526003600482015233600160a060020a031660248201529051731deeda36e15ec9e80f3d7414d67a4803ae45fc809163a0943154916044808301926020929190829003018160008760325a03f215610002575050604051511590506107f157604080517f7e9265620000000000000000000000000000000000000000000000000000000081526003600482015233600160a060020a031660248201529051731deeda36e15ec9e80f3d7414d67a4803ae45fc8091637e9265629160448083019260009291908290030181838760325a03f215610002575050505b565b6108686004356000731deeda36e15ec9e80f3d7414d67a4803ae45fc8063f5562753836040518260e060020a0281526004018082815260200191505060206040518083038160008760325a03f215610002575050604051519150505b919050565b610a1f600354600160a060020a03166101cc565b60408051918252519081900360200190f35b60045460006002600183161561010002600019019092169190910411156108a45760009150610994565b6108ac6105cf565b9050600081141580156108c0575060018114155b80156108cd575060028114155b156108db5760009150610994565b600480546000828152602060026001841615610100026000190190931692909204601f908101929092047f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19b9081019236929083901061095d5782800160ff198235161785555b5061098d9291505b808211156109945760008155600101610949565b82800160010185558215610941579182015b8281111561094157823582600050559160200191906001019061096f565b5050600191505b5090565b6040805161ffff9092168252519081900360200190f35b60405180806020018281038252838181518152602001915080519060200190808383829060006004602084601f0104600f02600301f150905090810190601f168015610a0f5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b005b60408051600160a060020a03929092168252519081900360200190f35b6040805160ff9092168252519081900360200190f35b820191906000526020600020905b815481529060010190602001808311610a6057829003601f168201915b505050505090506101cc565b6004546000600260018316156101000260001901909216919091041115610ab35760009150610994565b610abb6105cf565b905060008114158015610acf575060018114155b8015610adc575060028114155b15610aea5760009150610994565b604080517f7c0278fc000000000000000000000000000000000000000000000000000000008152600360048201818152602483019384523660448401819052731deeda36e15ec9e80f3d7414d67a4803ae45fc8094637c0278fc946000939190606401848480828437820191505094505050505060006040518083038160008760325a03f215610002575050505090565b1415610c8557604080516001547f0fee183d0000000000000000000000000000000000000000000000000000000082526003600483015233600160a060020a0316602483015234604483015260648201529051731deeda36e15ec9e80f3d7414d67a4803ae45fc8091630fee183d916084828101926020929190829003018160008760325a03f21561000257505060405151925050811515610c8a577389efe605e9ecbe22849cd85d5449cc946c26f8f36312c82bcc33346040518360e060020a0281526004018083600160a060020a031681526020018281526020019250505060206040518083038160008760325a03f2156100025750506040515115159050610c8a57610002565b505090565b81925050610994565b505b50565b1415610c93575a9150610cab3383610481565b1515610cb75750610c95565b731deeda36e15ec9e80f3d7414d67a4803ae45fc8063da46be0a60038433610cdd61046e565b610ce5610232565b6040518660e060020a0281526004018086815260200185815260200184600160a060020a031681526020018381526020018281526020019550505050505060006040518083038160008760325a03f21561000257505050610c933360408051600080547fc17e6817000000000000000000000000000000000000000000000000000000008352600160a060020a03908116600484015230163160248301529151731deeda36e15ec9e80f3d7414d67a4803ae45fc809263c17e68179260448082019360209390928390039091019082908760325a03f2156100025750505050565b30600160a060020a031660405180807f5f5f6469672875696e7432353629000000000000000000000000000000000000815260200150600e019050604051809103902060e060020a8091040260e060020a9004600184036040518260e060020a0281526004018082815260200191505060006040518083038160008760325a03f292505050151561084f5761000256" + "code": "0x606060405236156101a05760e060020a60003504630924120081146101c25780630a16697a146101cf5780630fd1f94e146101d8578063137c638b1461022e57806321835af61461023b57806324032866146102545780632f95b833146102d65780633017fe24146102e55780633233c686146102ef57806337f4c00e146102fa5780634500054f146103055780634e417a98146103785780634e71d92d146103e15780634f059a43146103f35780636146195414610451578063625cc4651461046157806367ce940d1461046a5780637d298ee314610477578063830953ab146104f9578063938b5f321461050457806395ee122114610516578063974654f41461052a578063a06db7dc14610535578063a9d2293d14610541578063ae45850b14610597578063b0f07e44146105a9578063c19d93fb146105cb578063c6502da81461062e578063c680362214610637578063ca94692d1461064a578063cc3471af14610673578063d379be23146106c9578063d62457f6146106e3578063ea8a1af0146106ee578063f5562753146107f3578063f6b4dfb414610854575b610868600080548190600160a060020a03908116339091161461087a57610994565b610868600b5460ff165b90565b610868600d5481565b6108686000731deeda36e15ec9e80f3d7414d67a4803ae45fc80630fd1f94e6040518160e060020a02815260040180905060206040518083038160008760325a03f2156100025750506040515191506101cc9050565b6108685b62012cc86101cc565b61086860043560008160001415610dc65750600161084f565b6108686004356024356000731deeda36e15ec9e80f3d7414d67a4803ae45fc80630bd295e6600360005085856040518460e060020a0281526004018084815260200183600160a060020a03168152602001828152602001935050505060206040518083038160008760325a03f215610002575050604051519150505b92915050565b61099860085461ffff166101cc565b61086860026101cc565b610868600a546101cc565b6108686006546101cc565b6108686000731deeda36e15ec9e80f3d7414d67a4803ae45fc8063a09431546003600050336040518360e060020a0281526004018083815260200182600160a060020a031681526020019250505060206040518083038160008760325a03f2156100025750506040515191506101cc9050565b6109af60408051602081810183526000825282516004805460026001821615610100026000190190911604601f81018490048402830184019095528482529293909291830182828015610a7d5780601f10610a5257610100808354040283529160200191610a7d565b61086860006000600180610b7b6105cf565b6108686000731deeda36e15ec9e80f3d7414d67a4803ae45fc8063f5562753436040518260e060020a0281526004018082815260200191505060206040518083038160008760325a03f2156100025750506040515191506101cc9050565b610a1d6000600480610c986105cf565b61086860025481565b6108685b620186a06101cc565b6108686004356024355b6000731deeda36e15ec9e80f3d7414d67a4803ae45fc8063a1873db6600360005085856040518460e060020a0281526004018084815260200183600160a060020a03168152602001828152602001935050505060206040518083038160008760325a03f2156100025750506040515191506102d09050565b6108686009546101cc565b610a1f600c54600160a060020a031681565b610868600b5462010000900460ff166101cc565b6108686007546101cc565b610a3c600e5460ff1681565b6108686000731deeda36e15ec9e80f3d7414d67a4803ae45fc8063a9d2293d6040518160e060020a02815260040180905060206040518083038160008760325a03f2156100025750506040515191506101cc9050565b610a1f600054600160a060020a031681565b610868600080548190600160a060020a039081163390911614610a8957610994565b6108685b6000731deeda36e15ec9e80f3d7414d67a4803ae45fc80635054d98a60036000506040518260e060020a0281526004018082815260200191505060206040518083038160008760325a03f2156100025750506040515191506101cc9050565b61086860015481565b610868600b54610100900460ff166101cc565b61086860035474010000000000000000000000000000000000000000900460e060020a026101cc565b6108686000731deeda36e15ec9e80f3d7414d67a4803ae45fc8063cc3471af6040518160e060020a02815260040180905060206040518083038160008760325a03f2156100025750506040515191506101cc9050565b610a1f600854620100009004600160a060020a03166101cc565b6108686005546101cc565b610a1d604080517fa09431540000000000000000000000000000000000000000000000000000000081526003600482015233600160a060020a031660248201529051731deeda36e15ec9e80f3d7414d67a4803ae45fc809163a0943154916044808301926020929190829003018160008760325a03f215610002575050604051511590506107f157604080517f7e9265620000000000000000000000000000000000000000000000000000000081526003600482015233600160a060020a031660248201529051731deeda36e15ec9e80f3d7414d67a4803ae45fc8091637e9265629160448083019260009291908290030181838760325a03f215610002575050505b565b6108686004356000731deeda36e15ec9e80f3d7414d67a4803ae45fc8063f5562753836040518260e060020a0281526004018082815260200191505060206040518083038160008760325a03f215610002575050604051519150505b919050565b610a1f600354600160a060020a03166101cc565b60408051918252519081900360200190f35b60045460006002600183161561010002600019019092169190910411156108a45760009150610994565b6108ac6105cf565b9050600081141580156108c0575060018114155b80156108cd575060028114155b156108db5760009150610994565b600480546000828152602060026001841615610100026000190190931692909204601f908101929092047f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19b9081019236929083901061095d5782800160ff198235161785555b5061098d9291505b808211156109945760008155600101610949565b82800160010185558215610941579182015b8281111561094157823582600050559160200191906001019061096f565b5050600191505b5090565b6040805161ffff9092168252519081900360200190f35b60405180806020018281038252838181518152602001915080519060200190808383829060006004602084601f0104600f02600301f150905090810190601f168015610a0f5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b005b60408051600160a060020a03929092168252519081900360200190f35b6040805160ff9092168252519081900360200190f35b820191906000526020600020905b815481529060010190602001808311610a6057829003601f168201915b505050505090506101cc565b6004546000600260018316156101000260001901909216919091041115610ab35760009150610994565b610abb6105cf565b905060008114158015610acf575060018114155b8015610adc575060028114155b15610aea5760009150610994565b604080517f7c0278fc000000000000000000000000000000000000000000000000000000008152600360048201818152602483019384523660448401819052731deeda36e15ec9e80f3d7414d67a4803ae45fc8094637c0278fc946000939190606401848480828437820191505094505050505060006040518083038160008760325a03f215610002575050505090565b1415610c8557604080516001547f0fee183d0000000000000000000000000000000000000000000000000000000082526003600483015233600160a060020a0316602483015234604483015260648201529051731deeda36e15ec9e80f3d7414d67a4803ae45fc8091630fee183d916084828101926020929190829003018160008760325a03f21561000257505060405151925050811515610c8a577389efe605e9ecbe22849cd85d5449cc946c26f8f36312c82bcc33346040518360e060020a0281526004018083600160a060020a031681526020018281526020019250505060206040518083038160008760325a03f2156100025750506040515115159050610c8a57610002565b505090565b81925050610994565b505b50565b1415610c93575a9150610cab3383610481565b1515610cb75750610c95565b731deeda36e15ec9e80f3d7414d67a4803ae45fc8063da46be0a60038433610cdd61046e565b610ce5610232565b6040518660e060020a0281526004018086815260200185815260200184600160a060020a031681526020018381526020018281526020019550505050505060006040518083038160008760325a03f21561000257505050610c933360408051600080547fc17e6817000000000000000000000000000000000000000000000000000000008352600160a060020a03908116600484015230163160248301529151731deeda36e15ec9e80f3d7414d67a4803ae45fc809263c17e68179260448082019360209390928390039091019082908760325a03f2156100025750505050565b30600160a060020a031660405180807f5f5f6469672875696e7432353629000000000000000000000000000000000000815260200150600e019050604051809103902060e060020a8091040260e060020a9004600184036040518260e060020a0281526004018082815260200191505060006040518083038160008760325a03f292505050151561084f5761000256", + "codeHash": "0x7678943ba1f399d76abe8e77b6f899c193f72aaefb5c4bd47fffb63c7f57ad9e" }, "0x7dd677b54fc954824a7bc49bd26cbdfa12c75adf": { "balance": "0xd7a58f5b73b4b6c4", "code": "0x606060405236156100985760e060020a60003504633896002781146100e15780633defb962146100ea5780633f4be8891461010c5780634136aa351461011f5780634a420138146101a057806369c1a7121461028c5780638129fc1c146102955780638da5cb5b146102a6578063ae45850b146102b8578063af3309d8146102cc578063ea8a1af0146102d5578063ead50da3146102f4575b610308671bc16d674ec8000030600160a060020a03163110156100df57600554604051600160a060020a03918216916000913091909116319082818181858883f150505050505b565b61030a60005481565b610308671bc16d674ec8000030600160a060020a031631101561040f576100df565b61031c600454600160a060020a03165b90565b61030a5b600080548190118015610199575060408051600480547f0a16697a0000000000000000000000000000000000000000000000000000000083529251600160a060020a039390931692630a16697a928083019260209291829003018187876161da5a03f1156100025750506040515160ff01431090505b905061011c565b6103085b600354600554604080517f8c0e156d0000000000000000000000000000000000000000000000000000000081527f3defb96200000000000000000000000000000000000000000000000000000000600482015260a060020a90920461ffff1643016024830152621e8480604483015251600092600160a060020a031691638c0e156d916729a2241af62c000091606481810192602092909190829003018185886185025a03f1156100025750506040515192600160a060020a0384161491506102899050576004805473ffffffffffffffffffffffffffffffffffffffff1916821790555b50565b61030a60015481565b61030860008054146103f2576100df565b61031c600554600160a060020a031681565b61031c600354600160a060020a031661011c565b61030a60025481565b610308600554600160a060020a03908116339091161461035157610002565b61033960055460a060020a900461ffff1681565b005b60408051918252519081900360200190f35b60408051600160a060020a03929092168252519081900360200190f35b6040805161ffff929092168252519081900360200190f35b6004546000600160a060020a03919091163111156103c75760408051600480547fea8a1af00000000000000000000000000000000000000000000000000000000083529251600160a060020a03939093169263ea8a1af0928083019260009291829003018183876161da5a03f115610002575050505b600554604051600160a060020a03918216916000913091909116319082818181858883f15050505050565b426000556100df6101a4565b600280546001908101909155429055565b600454600160a060020a03908116339091161461042b576100df565b610433610123565b151561043e576100df565b6103fe6101a456", + "codeHash": "0xd1255e5eabbe40c6e18c87b2ed2acf8157356103d1ca1df617f7b52811edefc4", "storage": { "0x0000000000000000000000000000000000000000000000000000000000000001": "0x0000000000000000000000000000000000000000000000000000000056d0009b", "0x0000000000000000000000000000000000000000000000000000000000000002": "0x000000000000000000000000000000000000000000000000000000000000008b", @@ -253,6 +256,7 @@ "0x651913977e8140c323997fce5e03c19e0015eebf": { "balance": "0x29a2241af62c0000", "code": "0x606060405236156101a05760e060020a60003504630924120081146101c25780630a16697a146101cf5780630fd1f94e146101d8578063137c638b1461022e57806321835af61461023b57806324032866146102545780632f95b833146102d65780633017fe24146102e55780633233c686146102ef57806337f4c00e146102fa5780634500054f146103055780634e417a98146103785780634e71d92d146103e15780634f059a43146103f35780636146195414610451578063625cc4651461046157806367ce940d1461046a5780637d298ee314610477578063830953ab146104f9578063938b5f321461050457806395ee122114610516578063974654f41461052a578063a06db7dc14610535578063a9d2293d14610541578063ae45850b14610597578063b0f07e44146105a9578063c19d93fb146105cb578063c6502da81461062e578063c680362214610637578063ca94692d1461064a578063cc3471af14610673578063d379be23146106c9578063d62457f6146106e3578063ea8a1af0146106ee578063f5562753146107f3578063f6b4dfb414610854575b610868600080548190600160a060020a03908116339091161461087a57610994565b610868600b5460ff165b90565b610868600d5481565b6108686000731deeda36e15ec9e80f3d7414d67a4803ae45fc80630fd1f94e6040518160e060020a02815260040180905060206040518083038160008760325a03f2156100025750506040515191506101cc9050565b6108685b62012cc86101cc565b61086860043560008160001415610dc65750600161084f565b6108686004356024356000731deeda36e15ec9e80f3d7414d67a4803ae45fc80630bd295e6600360005085856040518460e060020a0281526004018084815260200183600160a060020a03168152602001828152602001935050505060206040518083038160008760325a03f215610002575050604051519150505b92915050565b61099860085461ffff166101cc565b61086860026101cc565b610868600a546101cc565b6108686006546101cc565b6108686000731deeda36e15ec9e80f3d7414d67a4803ae45fc8063a09431546003600050336040518360e060020a0281526004018083815260200182600160a060020a031681526020019250505060206040518083038160008760325a03f2156100025750506040515191506101cc9050565b6109af60408051602081810183526000825282516004805460026001821615610100026000190190911604601f81018490048402830184019095528482529293909291830182828015610a7d5780601f10610a5257610100808354040283529160200191610a7d565b61086860006000600180610b7b6105cf565b6108686000731deeda36e15ec9e80f3d7414d67a4803ae45fc8063f5562753436040518260e060020a0281526004018082815260200191505060206040518083038160008760325a03f2156100025750506040515191506101cc9050565b610a1d6000600480610c986105cf565b61086860025481565b6108685b620186a06101cc565b6108686004356024355b6000731deeda36e15ec9e80f3d7414d67a4803ae45fc8063a1873db6600360005085856040518460e060020a0281526004018084815260200183600160a060020a03168152602001828152602001935050505060206040518083038160008760325a03f2156100025750506040515191506102d09050565b6108686009546101cc565b610a1f600c54600160a060020a031681565b610868600b5462010000900460ff166101cc565b6108686007546101cc565b610a3c600e5460ff1681565b6108686000731deeda36e15ec9e80f3d7414d67a4803ae45fc8063a9d2293d6040518160e060020a02815260040180905060206040518083038160008760325a03f2156100025750506040515191506101cc9050565b610a1f600054600160a060020a031681565b610868600080548190600160a060020a039081163390911614610a8957610994565b6108685b6000731deeda36e15ec9e80f3d7414d67a4803ae45fc80635054d98a60036000506040518260e060020a0281526004018082815260200191505060206040518083038160008760325a03f2156100025750506040515191506101cc9050565b61086860015481565b610868600b54610100900460ff166101cc565b61086860035474010000000000000000000000000000000000000000900460e060020a026101cc565b6108686000731deeda36e15ec9e80f3d7414d67a4803ae45fc8063cc3471af6040518160e060020a02815260040180905060206040518083038160008760325a03f2156100025750506040515191506101cc9050565b610a1f600854620100009004600160a060020a03166101cc565b6108686005546101cc565b610a1d604080517fa09431540000000000000000000000000000000000000000000000000000000081526003600482015233600160a060020a031660248201529051731deeda36e15ec9e80f3d7414d67a4803ae45fc809163a0943154916044808301926020929190829003018160008760325a03f215610002575050604051511590506107f157604080517f7e9265620000000000000000000000000000000000000000000000000000000081526003600482015233600160a060020a031660248201529051731deeda36e15ec9e80f3d7414d67a4803ae45fc8091637e9265629160448083019260009291908290030181838760325a03f215610002575050505b565b6108686004356000731deeda36e15ec9e80f3d7414d67a4803ae45fc8063f5562753836040518260e060020a0281526004018082815260200191505060206040518083038160008760325a03f215610002575050604051519150505b919050565b610a1f600354600160a060020a03166101cc565b60408051918252519081900360200190f35b60045460006002600183161561010002600019019092169190910411156108a45760009150610994565b6108ac6105cf565b9050600081141580156108c0575060018114155b80156108cd575060028114155b156108db5760009150610994565b600480546000828152602060026001841615610100026000190190931692909204601f908101929092047f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19b9081019236929083901061095d5782800160ff198235161785555b5061098d9291505b808211156109945760008155600101610949565b82800160010185558215610941579182015b8281111561094157823582600050559160200191906001019061096f565b5050600191505b5090565b6040805161ffff9092168252519081900360200190f35b60405180806020018281038252838181518152602001915080519060200190808383829060006004602084601f0104600f02600301f150905090810190601f168015610a0f5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b005b60408051600160a060020a03929092168252519081900360200190f35b6040805160ff9092168252519081900360200190f35b820191906000526020600020905b815481529060010190602001808311610a6057829003601f168201915b505050505090506101cc565b6004546000600260018316156101000260001901909216919091041115610ab35760009150610994565b610abb6105cf565b905060008114158015610acf575060018114155b8015610adc575060028114155b15610aea5760009150610994565b604080517f7c0278fc000000000000000000000000000000000000000000000000000000008152600360048201818152602483019384523660448401819052731deeda36e15ec9e80f3d7414d67a4803ae45fc8094637c0278fc946000939190606401848480828437820191505094505050505060006040518083038160008760325a03f215610002575050505090565b1415610c8557604080516001547f0fee183d0000000000000000000000000000000000000000000000000000000082526003600483015233600160a060020a0316602483015234604483015260648201529051731deeda36e15ec9e80f3d7414d67a4803ae45fc8091630fee183d916084828101926020929190829003018160008760325a03f21561000257505060405151925050811515610c8a577389efe605e9ecbe22849cd85d5449cc946c26f8f36312c82bcc33346040518360e060020a0281526004018083600160a060020a031681526020018281526020019250505060206040518083038160008760325a03f2156100025750506040515115159050610c8a57610002565b505090565b81925050610994565b505b50565b1415610c93575a9150610cab3383610481565b1515610cb75750610c95565b731deeda36e15ec9e80f3d7414d67a4803ae45fc8063da46be0a60038433610cdd61046e565b610ce5610232565b6040518660e060020a0281526004018086815260200185815260200184600160a060020a031681526020018381526020018281526020019550505050505060006040518083038160008760325a03f21561000257505050610c933360408051600080547fc17e6817000000000000000000000000000000000000000000000000000000008352600160a060020a03908116600484015230163160248301529151731deeda36e15ec9e80f3d7414d67a4803ae45fc809263c17e68179260448082019360209390928390039091019082908760325a03f2156100025750505050565b30600160a060020a031660405180807f5f5f6469672875696e7432353629000000000000000000000000000000000000815260200150600e019050604051809103902060e060020a8091040260e060020a9004600184036040518260e060020a0281526004018082815260200191505060006040518083038160008760325a03f292505050151561084f5761000256", + "codeHash": "0x7678943ba1f399d76abe8e77b6f899c193f72aaefb5c4bd47fffb63c7f57ad9e", "storage": { "0x0000000000000000000000000000000000000000000000000000000000000000": "0x0000000000000000000000007dd677b54fc954824a7bc49bd26cbdfa12c75adf", "0x0000000000000000000000000000000000000000000000000000000000000001": "0x0000000000000000000000000000000000000000000000000011f8119429ed3a", diff --git a/eth/tracers/internal/tracetest/testdata/prestate_tracer_with_diff_mode/inner_create_disable_code_and_storage.json b/eth/tracers/internal/tracetest/testdata/prestate_tracer_with_diff_mode/inner_create_disable_code_and_storage.json index 96c93e7cf8..9b6b7577f9 100644 --- a/eth/tracers/internal/tracetest/testdata/prestate_tracer_with_diff_mode/inner_create_disable_code_and_storage.json +++ b/eth/tracers/internal/tracetest/testdata/prestate_tracer_with_diff_mode/inner_create_disable_code_and_storage.json @@ -211,13 +211,16 @@ }, "0x6c8f2a135f6ed072de4503bd7c4999a1a17f824b": { "balance": "0x0", - "nonce": 237 + "nonce": 237, + "codeHash":"0x461e17b7ae561793f22843985fc6866a3395c1fcee8ebf2d7ed5f293aec1b473" }, "0x741467b251fca923d6229c4b439078b55dca233b": { - "balance": "0x29c613529e8218f8" + "balance": "0x29c613529e8218f8", + "codeHash":"0x7678943ba1f399d76abe8e77b6f899c193f72aaefb5c4bd47fffb63c7f57ad9e" }, "0x7dd677b54fc954824a7bc49bd26cbdfa12c75adf": { - "balance": "0xd7a58f5b73b4b6c4" + "balance": "0xd7a58f5b73b4b6c4", + "codeHash":"0xd1255e5eabbe40c6e18c87b2ed2acf8157356103d1ca1df617f7b52811edefc4" }, "0xb834e3edfc1a927bdcecb67a9d0eccbd752a5bb3": { "balance": "0xffe9b09a5c474dca", @@ -233,7 +236,8 @@ "balance": "0x98e2b02f14529b1eb2" }, "0x651913977e8140c323997fce5e03c19e0015eebf": { - "balance": "0x29a2241af62c0000" + "balance": "0x29a2241af62c0000", + "codeHash":"0x7678943ba1f399d76abe8e77b6f899c193f72aaefb5c4bd47fffb63c7f57ad9e" }, "0x6c8f2a135f6ed072de4503bd7c4999a1a17f824b": { "nonce": 238 diff --git a/eth/tracers/internal/tracetest/testdata/prestate_tracer_with_diff_mode/simple.json b/eth/tracers/internal/tracetest/testdata/prestate_tracer_with_diff_mode/simple.json index be4981b8b8..c97e16bce5 100644 --- a/eth/tracers/internal/tracetest/testdata/prestate_tracer_with_diff_mode/simple.json +++ b/eth/tracers/internal/tracetest/testdata/prestate_tracer_with_diff_mode/simple.json @@ -68,6 +68,7 @@ "balance": "0x4d87094125a369d9bd5", "nonce": 1, "code": "0x606060405236156100935763ffffffff60e060020a60003504166311ee8382811461009c57806313af4035146100be5780631f5e8f4c146100ee57806324daddc5146101125780634921a91a1461013b57806363e4bff414610157578063764978f91461017f578063893d20e8146101a1578063ba40aaa1146101cd578063cebc9a82146101f4578063e177246e14610216575b61009a5b5b565b005b34156100a457fe5b6100ac61023d565b60408051918252519081900360200190f35b34156100c657fe5b6100da600160a060020a0360043516610244565b604080519115158252519081900360200190f35b34156100f657fe5b6100da610307565b604080519115158252519081900360200190f35b341561011a57fe5b6100da6004351515610318565b604080519115158252519081900360200190f35b6100da6103d6565b604080519115158252519081900360200190f35b6100da600160a060020a0360043516610420565b604080519115158252519081900360200190f35b341561018757fe5b6100ac61046c565b60408051918252519081900360200190f35b34156101a957fe5b6101b1610473565b60408051600160a060020a039092168252519081900360200190f35b34156101d557fe5b6100da600435610483565b604080519115158252519081900360200190f35b34156101fc57fe5b6100ac61050d565b60408051918252519081900360200190f35b341561021e57fe5b6100da600435610514565b604080519115158252519081900360200190f35b6003545b90565b60006000610250610473565b600160a060020a031633600160a060020a03161415156102705760006000fd5b600160a060020a03831615156102865760006000fd5b50600054600160a060020a0390811690831681146102fb57604051600160a060020a0380851691908316907ffcf23a92150d56e85e3a3d33b357493246e55783095eb6a733eb8439ffc752c890600090a360008054600160a060020a031916600160a060020a03851617905560019150610300565b600091505b5b50919050565b60005460a060020a900460ff165b90565b60006000610324610473565b600160a060020a031633600160a060020a03161415156103445760006000fd5b5060005460a060020a900460ff16801515831515146102fb576000546040805160a060020a90920460ff1615158252841515602083015280517fe6cd46a119083b86efc6884b970bfa30c1708f53ba57b86716f15b2f4551a9539281900390910190a16000805460a060020a60ff02191660a060020a8515150217905560019150610300565b600091505b5b50919050565b60006103e0610307565b801561040557506103ef610473565b600160a060020a031633600160a060020a031614155b156104105760006000fd5b610419336105a0565b90505b5b90565b600061042a610307565b801561044f5750610439610473565b600160a060020a031633600160a060020a031614155b1561045a5760006000fd5b610463826105a0565b90505b5b919050565b6001545b90565b600054600160a060020a03165b90565b6000600061048f610473565b600160a060020a031633600160a060020a03161415156104af5760006000fd5b506001548281146102fb57604080518281526020810185905281517f79a3746dde45672c9e8ab3644b8bb9c399a103da2dc94b56ba09777330a83509929181900390910190a160018381559150610300565b600091505b5b50919050565b6002545b90565b60006000610520610473565b600160a060020a031633600160a060020a03161415156105405760006000fd5b506002548281146102fb57604080518281526020810185905281517ff6991a728965fedd6e927fdf16bdad42d8995970b4b31b8a2bf88767516e2494929181900390910190a1600283905560019150610300565b600091505b5b50919050565b60006000426105ad61023d565b116102fb576105c46105bd61050d565b4201610652565b6105cc61046c565b604051909150600160a060020a038416908290600081818185876187965a03f1925050501561063d57604080518281529051600160a060020a038516917f9bca65ce52fdef8a470977b51f247a2295123a4807dfa9e502edf0d30722da3b919081900360200190a260019150610300565b6102fb42610652565b5b600091505b50919050565b60038190555b505600a165627a7a72305820f3c973c8b7ed1f62000b6701bd5b708469e19d0f1d73fde378a56c07fd0b19090029", + "codeHash": "0xec0ba40983fafc34be1bda1b3a3c6eabdd60fa4ce6eab345be1e51bda01d0d4f", "storage": { "0x0000000000000000000000000000000000000000000000000000000000000003": "0x000000000000000000000000000000000000000000000000000000005a37b834" } diff --git a/eth/tracers/internal/tracetest/testdata/prestate_tracer_with_diff_mode/simple_disable_code_and_storage.json b/eth/tracers/internal/tracetest/testdata/prestate_tracer_with_diff_mode/simple_disable_code_and_storage.json index 502149de43..9041901790 100644 --- a/eth/tracers/internal/tracetest/testdata/prestate_tracer_with_diff_mode/simple_disable_code_and_storage.json +++ b/eth/tracers/internal/tracetest/testdata/prestate_tracer_with_diff_mode/simple_disable_code_and_storage.json @@ -67,6 +67,7 @@ "balance": "0x4d87094125a369d9bd5", "nonce": 1, "code": "0x606060405236156100935763ffffffff60e060020a60003504166311ee8382811461009c57806313af4035146100be5780631f5e8f4c146100ee57806324daddc5146101125780634921a91a1461013b57806363e4bff414610157578063764978f91461017f578063893d20e8146101a1578063ba40aaa1146101cd578063cebc9a82146101f4578063e177246e14610216575b61009a5b5b565b005b34156100a457fe5b6100ac61023d565b60408051918252519081900360200190f35b34156100c657fe5b6100da600160a060020a0360043516610244565b604080519115158252519081900360200190f35b34156100f657fe5b6100da610307565b604080519115158252519081900360200190f35b341561011a57fe5b6100da6004351515610318565b604080519115158252519081900360200190f35b6100da6103d6565b604080519115158252519081900360200190f35b6100da600160a060020a0360043516610420565b604080519115158252519081900360200190f35b341561018757fe5b6100ac61046c565b60408051918252519081900360200190f35b34156101a957fe5b6101b1610473565b60408051600160a060020a039092168252519081900360200190f35b34156101d557fe5b6100da600435610483565b604080519115158252519081900360200190f35b34156101fc57fe5b6100ac61050d565b60408051918252519081900360200190f35b341561021e57fe5b6100da600435610514565b604080519115158252519081900360200190f35b6003545b90565b60006000610250610473565b600160a060020a031633600160a060020a03161415156102705760006000fd5b600160a060020a03831615156102865760006000fd5b50600054600160a060020a0390811690831681146102fb57604051600160a060020a0380851691908316907ffcf23a92150d56e85e3a3d33b357493246e55783095eb6a733eb8439ffc752c890600090a360008054600160a060020a031916600160a060020a03851617905560019150610300565b600091505b5b50919050565b60005460a060020a900460ff165b90565b60006000610324610473565b600160a060020a031633600160a060020a03161415156103445760006000fd5b5060005460a060020a900460ff16801515831515146102fb576000546040805160a060020a90920460ff1615158252841515602083015280517fe6cd46a119083b86efc6884b970bfa30c1708f53ba57b86716f15b2f4551a9539281900390910190a16000805460a060020a60ff02191660a060020a8515150217905560019150610300565b600091505b5b50919050565b60006103e0610307565b801561040557506103ef610473565b600160a060020a031633600160a060020a031614155b156104105760006000fd5b610419336105a0565b90505b5b90565b600061042a610307565b801561044f5750610439610473565b600160a060020a031633600160a060020a031614155b1561045a5760006000fd5b610463826105a0565b90505b5b919050565b6001545b90565b600054600160a060020a03165b90565b6000600061048f610473565b600160a060020a031633600160a060020a03161415156104af5760006000fd5b506001548281146102fb57604080518281526020810185905281517f79a3746dde45672c9e8ab3644b8bb9c399a103da2dc94b56ba09777330a83509929181900390910190a160018381559150610300565b600091505b5b50919050565b6002545b90565b60006000610520610473565b600160a060020a031633600160a060020a03161415156105405760006000fd5b506002548281146102fb57604080518281526020810185905281517ff6991a728965fedd6e927fdf16bdad42d8995970b4b31b8a2bf88767516e2494929181900390910190a1600283905560019150610300565b600091505b5b50919050565b60006000426105ad61023d565b116102fb576105c46105bd61050d565b4201610652565b6105cc61046c565b604051909150600160a060020a038416908290600081818185876187965a03f1925050501561063d57604080518281529051600160a060020a038516917f9bca65ce52fdef8a470977b51f247a2295123a4807dfa9e502edf0d30722da3b919081900360200190a260019150610300565b6102fb42610652565b5b600091505b50919050565b60038190555b505600a165627a7a72305820f3c973c8b7ed1f62000b6701bd5b708469e19d0f1d73fde378a56c07fd0b19090029", + "codeHash": "0xec0ba40983fafc34be1bda1b3a3c6eabdd60fa4ce6eab345be1e51bda01d0d4f", "storage": { "0x0000000000000000000000000000000000000000000000000000000000000003": "0x000000000000000000000000000000000000000000000000000000005a37b834" } diff --git a/eth/tracers/internal/tracetest/testdata/prestate_tracer_with_diff_mode/suicide.json b/eth/tracers/internal/tracetest/testdata/prestate_tracer_with_diff_mode/suicide.json index 3f07146871..23ac6852d9 100644 --- a/eth/tracers/internal/tracetest/testdata/prestate_tracer_with_diff_mode/suicide.json +++ b/eth/tracers/internal/tracetest/testdata/prestate_tracer_with_diff_mode/suicide.json @@ -79,6 +79,7 @@ "0x2861bf89b6c640c79040d357c1e9513693ef5d3f": { "balance": "0x0", "code": "0x606060405236156100825760e060020a600035046312055e8f8114610084578063185061da146100b157806322beb9b9146100d5578063245a03ec146101865780633fa4f245146102a657806341c0e1b5146102af578063890eba68146102cb578063b29f0835146102de578063d6b4485914610308578063dd012a15146103b9575b005b6001805474ff0000000000000000000000000000000000000000191660a060020a60043502179055610082565b6100826001805475ff00000000000000000000000000000000000000000019169055565b61008260043560015460e060020a6352afbc3302606090815230600160a060020a039081166064527fb29f0835000000000000000000000000000000000000000000000000000000006084527fc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a47060a45243840160c490815260ff60a060020a85041660e452600061010481905291909316926352afbc339261012492918183876161da5a03f1156100025750505050565b6100826004356024356001547fb0f07e440000000000000000000000000000000000000000000000000000000060609081526064839052600160a060020a039091169063b0f07e449060849060009060248183876161da5a03f150604080516001547f73657449742875696e74323536290000000000000000000000000000000000008252825191829003600e018220878352835192839003602001832060e060020a6352afbc33028452600160a060020a03308116600486015260e060020a9283900490920260248501526044840152438901606484015260a060020a820460ff1694830194909452600060a483018190529251931694506352afbc33935060c48181019391829003018183876161da5a03f115610002575050505050565b6103c460025481565b61008260005433600160a060020a039081169116146103ce575b565b6103c460015460a860020a900460ff1681565b6100826001805475ff000000000000000000000000000000000000000000191660a860020a179055565b61008260043560015460e060020a6352afbc3302606090815230600160a060020a039081166064527f185061da000000000000000000000000000000000000000000000000000000006084527fc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a47060a45243840160c490815260ff60a060020a85041660e452600061010481905291909316926352afbc339261012492918183876161da5a03f1156100025750505050565b600435600255610082565b6060908152602090f35b6001547f6ff96d17000000000000000000000000000000000000000000000000000000006060908152600160a060020a0330811660645290911690632e1a7d4d908290636ff96d17906084906020906024816000876161da5a03f1156100025750506040805180517f2e1a7d4d0000000000000000000000000000000000000000000000000000000082526004820152905160248281019350600092829003018183876161da5a03f115610002575050600054600160a060020a03169050ff", + "codeHash": "0xad3e5642a709b936c0eafdd1fbca08a9f5f5089ff2008efeee3eed3f110d83d3", "storage": { "0x0000000000000000000000000000000000000000000000000000000000000000": "0x000000000000000000000000d3cda913deb6f67967b99d67acdfa1712c293601", "0x0000000000000000000000000000000000000000000000000000000000000001": "0x0000000000000000000000ff30c9e568f133adce1f1ea91e189613223fc461b9" diff --git a/eth/tracers/native/gen_account_json.go b/eth/tracers/native/gen_account_json.go index 4c39cbc38c..5fec2648b7 100644 --- a/eth/tracers/native/gen_account_json.go +++ b/eth/tracers/native/gen_account_json.go @@ -15,14 +15,16 @@ var _ = (*accountMarshaling)(nil) // MarshalJSON marshals as JSON. func (a account) MarshalJSON() ([]byte, error) { type account struct { - Balance *hexutil.Big `json:"balance,omitempty"` - Code hexutil.Bytes `json:"code,omitempty"` - Nonce uint64 `json:"nonce,omitempty"` - Storage map[common.Hash]common.Hash `json:"storage,omitempty"` + Balance *hexutil.Big `json:"balance,omitempty"` + Code hexutil.Bytes `json:"code,omitempty"` + CodeHash *common.Hash `json:"codeHash,omitempty"` + Nonce uint64 `json:"nonce,omitempty"` + Storage map[common.Hash]common.Hash `json:"storage,omitempty"` } var enc account enc.Balance = (*hexutil.Big)(a.Balance) enc.Code = a.Code + enc.CodeHash = a.CodeHash enc.Nonce = a.Nonce enc.Storage = a.Storage return json.Marshal(&enc) @@ -31,10 +33,11 @@ func (a account) MarshalJSON() ([]byte, error) { // UnmarshalJSON unmarshals from JSON. func (a *account) UnmarshalJSON(input []byte) error { type account struct { - Balance *hexutil.Big `json:"balance,omitempty"` - Code *hexutil.Bytes `json:"code,omitempty"` - Nonce *uint64 `json:"nonce,omitempty"` - Storage map[common.Hash]common.Hash `json:"storage,omitempty"` + Balance *hexutil.Big `json:"balance,omitempty"` + Code *hexutil.Bytes `json:"code,omitempty"` + CodeHash *common.Hash `json:"codeHash,omitempty"` + Nonce *uint64 `json:"nonce,omitempty"` + Storage map[common.Hash]common.Hash `json:"storage,omitempty"` } var dec account if err := json.Unmarshal(input, &dec); err != nil { @@ -46,6 +49,9 @@ func (a *account) UnmarshalJSON(input []byte) error { if dec.Code != nil { a.Code = *dec.Code } + if dec.CodeHash != nil { + a.CodeHash = dec.CodeHash + } if dec.Nonce != nil { a.Nonce = *dec.Nonce } diff --git a/eth/tracers/native/prestate.go b/eth/tracers/native/prestate.go index 57c66ae327..49679d312f 100644 --- a/eth/tracers/native/prestate.go +++ b/eth/tracers/native/prestate.go @@ -44,11 +44,12 @@ func init() { type stateMap = map[common.Address]*account type account struct { - Balance *big.Int `json:"balance,omitempty"` - Code []byte `json:"code,omitempty"` - Nonce uint64 `json:"nonce,omitempty"` - Storage map[common.Hash]common.Hash `json:"storage,omitempty"` - empty bool + Balance *big.Int `json:"balance,omitempty"` + Code []byte `json:"code,omitempty"` + CodeHash *common.Hash `json:"codeHash,omitempty"` + Nonce uint64 `json:"nonce,omitempty"` + Storage map[common.Hash]common.Hash `json:"storage,omitempty"` + empty bool } func (a *account) exists() bool { @@ -247,6 +248,7 @@ func (t *prestateTracer) processDiffState() { postAccount := &account{Storage: make(map[common.Hash]common.Hash)} newBalance := t.env.StateDB.GetBalance(addr).ToBig() newNonce := t.env.StateDB.GetNonce(addr) + newCodeHash := t.env.StateDB.GetCodeHash(addr) if newBalance.Cmp(t.pre[addr].Balance) != 0 { modified = true @@ -256,6 +258,19 @@ func (t *prestateTracer) processDiffState() { modified = true postAccount.Nonce = newNonce } + prevCodeHash := common.Hash{} + if t.pre[addr].CodeHash != nil { + prevCodeHash = *t.pre[addr].CodeHash + } + // Empty code hashes are excluded from the prestate. Normalize + // the empty code hash to a zero hash to make it comparable. + if newCodeHash == types.EmptyCodeHash { + newCodeHash = common.Hash{} + } + if newCodeHash != prevCodeHash { + modified = true + postAccount.CodeHash = &newCodeHash + } if !t.config.DisableCode { newCode := t.env.StateDB.GetCode(addr) if !bytes.Equal(newCode, t.pre[addr].Code) { @@ -305,6 +320,11 @@ func (t *prestateTracer) lookupAccount(addr common.Address) { Nonce: t.env.StateDB.GetNonce(addr), Code: t.env.StateDB.GetCode(addr), } + codeHash := t.env.StateDB.GetCodeHash(addr) + // If the code is empty, we don't need to store it in the prestate. + if codeHash != (common.Hash{}) && codeHash != types.EmptyCodeHash { + acc.CodeHash = &codeHash + } if !acc.exists() { acc.empty = true } From 3ff99ae52c420477020ae957a61c5c216ac7e7f5 Mon Sep 17 00:00:00 2001 From: Marius van der Wijden Date: Wed, 13 Aug 2025 17:12:08 +0200 Subject: [PATCH 45/57] eth/syncer: fix typo (#32427) avaibale -> available --- eth/syncer/syncer.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/eth/syncer/syncer.go b/eth/syncer/syncer.go index 5c4d2401e9..6e3918ce88 100644 --- a/eth/syncer/syncer.go +++ b/eth/syncer/syncer.go @@ -99,7 +99,7 @@ func (s *Syncer) run() { ) for { if retries >= 10 { - req.errc <- fmt.Errorf("sync target is not avaibale, %x", req.hash) + req.errc <- fmt.Errorf("sync target is not available, %x", req.hash) break } select { From 2b38daa48c92947a03830ee9d4319328bc710f4e Mon Sep 17 00:00:00 2001 From: cui Date: Thu, 14 Aug 2025 16:28:57 +0800 Subject: [PATCH 46/57] p2p: refactor to use time.Now().UnixMilli() in golang std lib (#32402) --- p2p/enode/localnode.go | 9 --------- p2p/enode/localnode_test.go | 3 ++- p2p/enode/nodedb.go | 2 +- 3 files changed, 3 insertions(+), 11 deletions(-) diff --git a/p2p/enode/localnode.go b/p2p/enode/localnode.go index d8fa6a9202..6425560b02 100644 --- a/p2p/enode/localnode.go +++ b/p2p/enode/localnode.go @@ -305,12 +305,3 @@ func (ln *LocalNode) bumpSeq() { ln.seq++ ln.db.storeLocalSeq(ln.id, ln.seq) } - -// nowMilliseconds gives the current timestamp at millisecond precision. -func nowMilliseconds() uint64 { - ns := time.Now().UnixNano() - if ns < 0 { - return 0 - } - return uint64(ns / 1000 / 1000) -} diff --git a/p2p/enode/localnode_test.go b/p2p/enode/localnode_test.go index 86b962a74e..5ddc302d65 100644 --- a/p2p/enode/localnode_test.go +++ b/p2p/enode/localnode_test.go @@ -21,6 +21,7 @@ import ( "net" "net/netip" "testing" + "time" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/p2p/enr" @@ -53,7 +54,7 @@ func TestLocalNode(t *testing.T) { // This test checks that the sequence number is persisted between restarts. func TestLocalNodeSeqPersist(t *testing.T) { - timestamp := nowMilliseconds() + timestamp := uint64(time.Now().UnixMilli()) ln, db := newLocalNodeForTesting() defer db.Close() diff --git a/p2p/enode/nodedb.go b/p2p/enode/nodedb.go index 51e554e68a..2cd211e2c2 100644 --- a/p2p/enode/nodedb.go +++ b/p2p/enode/nodedb.go @@ -434,7 +434,7 @@ func (db *DB) localSeq(id ID) uint64 { if seq := db.fetchUint64(localItemKey(id, dbLocalSeq)); seq > 0 { return seq } - return nowMilliseconds() + return uint64(time.Now().UnixMilli()) } // storeLocalSeq stores the local record sequence counter. From b00b6fe2345112c05b733ac8cacf417fb686cd04 Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Thu, 14 Aug 2025 13:07:20 +0200 Subject: [PATCH 47/57] .github: upgrade workflows to Go 1.25 (#32425) --- .github/workflows/go.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml index 13f97898bb..2ff47ce042 100644 --- a/.github/workflows/go.yml +++ b/.github/workflows/go.yml @@ -25,7 +25,7 @@ jobs: - name: Set up Go uses: actions/setup-go@v5 with: - go-version: 1.24 + go-version: 1.25 cache: false - name: Run linters @@ -41,8 +41,8 @@ jobs: strategy: matrix: go: + - '1.25' - '1.24' - - '1.23' steps: - uses: actions/checkout@v4 with: From 25cce4dfe469113bd6020c6b32f02cdd0d3d6630 Mon Sep 17 00:00:00 2001 From: levisyin Date: Thu, 14 Aug 2025 19:24:47 +0800 Subject: [PATCH 48/57] build: upgrade -dlgo version to Go 1.25.0 (#32412) --- build/checksums.txt | 94 ++++++++++++++++++++++----------------------- 1 file changed, 47 insertions(+), 47 deletions(-) diff --git a/build/checksums.txt b/build/checksums.txt index 7641b9ae62..ab0f7547f6 100644 --- a/build/checksums.txt +++ b/build/checksums.txt @@ -5,54 +5,54 @@ # https://github.com/ethereum/execution-spec-tests/releases/download/fusaka-devnet-3%40v1.0.0 576261e1280e5300c458aa9b05eccb2fec5ff80a0005940dc52fa03fdd907249 fixtures_fusaka-devnet-3.tar.gz -# version:golang 1.24.4 +# version:golang 1.25.0 # https://go.dev/dl/ -5a86a83a31f9fa81490b8c5420ac384fd3d95a3e71fba665c7b3f95d1dfef2b4 go1.24.4.src.tar.gz -0d2af78e3b6e08f8013dbbdb26ae33052697b6b72e03ec17d496739c2a1aed68 go1.24.4.aix-ppc64.tar.gz -69bef555e114b4a2252452b6e7049afc31fbdf2d39790b669165e89525cd3f5c go1.24.4.darwin-amd64.tar.gz -c4d74453a26f488bdb4b0294da4840d9020806de4661785334eb6d1803ee5c27 go1.24.4.darwin-amd64.pkg -27973684b515eaf461065054e6b572d9390c05e69ba4a423076c160165336470 go1.24.4.darwin-arm64.tar.gz -2fe1f8746745c4bfebd494583aaef24cad42594f6d25ed67856879d567ee66e7 go1.24.4.darwin-arm64.pkg -70b2de9c1cafe5af7be3eb8f80753cce0501ef300db3f3bd59be7ccc464234e1 go1.24.4.dragonfly-amd64.tar.gz -8d529839db29ee171505b89dc9c3de76003a4ab56202d84bddbbecacbfb6d7c9 go1.24.4.freebsd-386.tar.gz -6cbc3ad6cc21bdcc7283824d3ac0e85512c02022f6a35eb2e844882ea6e8448c go1.24.4.freebsd-amd64.tar.gz -d49ae050c20aff646a7641dd903f03eb674570790b90ffb298076c4d41e36655 go1.24.4.freebsd-arm.tar.gz -e31924abef2a28456b7103c0a5d333dcc11ecf19e76d5de1a383ad5fe0b42457 go1.24.4.freebsd-arm64.tar.gz -b5bca135eae8ebddf22972611ac1c58ae9fbb5979fd953cc5245c5b1b2517546 go1.24.4.freebsd-riscv64.tar.gz -7d5efda511ff7e3114b130acee5d0bffbb078fedbfa9b2c1b6a807107e1ca23a go1.24.4.illumos-amd64.tar.gz -130c9b061082eca15513e595e9952a2ded32e737e609dd0e49f7dfa74eba026d go1.24.4.linux-386.tar.gz -77e5da33bb72aeaef1ba4418b6fe511bc4d041873cbf82e5aa6318740df98717 go1.24.4.linux-amd64.tar.gz -d5501ee5aca0f258d5fe9bfaed401958445014495dc115f202d43d5210b45241 go1.24.4.linux-arm64.tar.gz -6a554e32301cecae3162677e66d4264b81b3b1a89592dd1b7b5c552c7a49fe37 go1.24.4.linux-armv6l.tar.gz -b208eb25fe244408cbe269ed426454bc46e59d0e0a749b6240d39e884e969875 go1.24.4.linux-loong64.tar.gz -fddfcb28fd36fe63d2ae181026798f86f3bbd3a7bb0f1e1f617dd3d604bf3fe4 go1.24.4.linux-mips.tar.gz -7934b924d5ab8c8ae3134a09a6ae74d3c39f63f6c4322ec289364dbbf0bac3ca go1.24.4.linux-mips64.tar.gz -fa763d8673f94d6e534bb72c3cf675d4c2b8da4a6da42a89f08c5586106db39c go1.24.4.linux-mips64le.tar.gz -84363dbfe49b41d43df84420a09bd53a4770053d63bfa509868c46a5f8eb3ff7 go1.24.4.linux-mipsle.tar.gz -28fcbd5d3b56493606873c33f2b4bdd84ba93c633f37313613b5a1e6495c6fe5 go1.24.4.linux-ppc64.tar.gz -9ca4afef813a2578c23843b640ae0290aa54b2e3c950a6cc4c99e16a57dec2ec go1.24.4.linux-ppc64le.tar.gz -1d7034f98662d8f2c8abd7c700ada4093acb4f9c00e0e51a30344821d0785c77 go1.24.4.linux-riscv64.tar.gz -0449f3203c39703ab27684be763e9bb78ca9a051e0e4176727aead9461b6deb5 go1.24.4.linux-s390x.tar.gz -954b49ccc2cfcf4b5f7cd33ff662295e0d3b74e7590c8e25fc2abb30bce120ba go1.24.4.netbsd-386.tar.gz -370fabcdfee7c18857c96fdd5b706e025d4fb86a208da88ba56b1493b35498e9 go1.24.4.netbsd-amd64.tar.gz -7935ef95d4d1acc48587b1eb4acab98b0a7d9569736a32398b9c1d2e89026865 go1.24.4.netbsd-arm.tar.gz -ead78fd0fa29fbb176cc83f1caa54032e1a44f842affa56a682c647e0759f237 go1.24.4.netbsd-arm64.tar.gz -913e217394b851a636b99de175f0c2f9ab9938b41c557f047168f77ee485d776 go1.24.4.openbsd-386.tar.gz -24568da3dcbcdb24ec18b631f072faf0f3763e3d04f79032dc56ad9ec35379c4 go1.24.4.openbsd-amd64.tar.gz -45abf523f870632417ab007de3841f64dd906bde546ffc8c6380ccbe91c7fb73 go1.24.4.openbsd-arm.tar.gz -7c57c69b5dd1e946b28a3034c285240a48e2861bdcb50b7d9c0ed61bcf89c879 go1.24.4.openbsd-arm64.tar.gz -91ed711f704829372d6931e1897631ef40288b8f9e3cd6ef4a24df7126d1066a go1.24.4.openbsd-ppc64.tar.gz -de5e270d971c8790e8880168d56a2ea103979927c10ded136d792bbdf9bce3d3 go1.24.4.openbsd-riscv64.tar.gz -ff429d03f00bcd32a50f445320b8329d0fadb2a2fff899c11e95e0922a82c543 go1.24.4.plan9-386.tar.gz -39d6363a43fd16b60ae9ad7346a264e982e4fa653dee3b45f83e03cd2f7a6647 go1.24.4.plan9-amd64.tar.gz -1964ae2571259de77b930e97f2891aa92706ff81aac9909d45bb107b0fab16c8 go1.24.4.plan9-arm.tar.gz -a7f9af424e8fb87886664754badca459513f64f6a321d17f1d219b8edf519821 go1.24.4.solaris-amd64.tar.gz -d454d3cb144432f1726bf00e28c6017e78ccb256a8d01b8e3fb1b2e6b5650f28 go1.24.4.windows-386.zip -966ecace1cdbb3497a2b930bdb0f90c3ad32922fa1a7c655b2d4bbeb7e4ac308 go1.24.4.windows-386.msi -b751a1136cb9d8a2e7ebb22c538c4f02c09b98138c7c8bfb78a54a4566c013b1 go1.24.4.windows-amd64.zip -0cbb6e83865747dbe69b3d4155f92e88fcf336ff5d70182dba145e9d7bd3d8f6 go1.24.4.windows-amd64.msi -d17da51bc85bd010754a4063215d15d2c033cc289d67ca9201a03c9041b2969d go1.24.4.windows-arm64.zip -47dbe734b6a829de45654648a7abcf05bdceef5c80e03ea0b208eeebef75a852 go1.24.4.windows-arm64.msi +4bd01e91297207bfa450ea40d4d5a93b1b531a5e438473b2a06e18e077227225 go1.25.0.src.tar.gz +e5234a7dac67bc86c528fe9752fc9d63557918627707a733ab4cac1a6faed2d4 go1.25.0.aix-ppc64.tar.gz +5bd60e823037062c2307c71e8111809865116714d6f6b410597cf5075dfd80ef go1.25.0.darwin-amd64.tar.gz +95e836238bcf8f9a71bffea43344cbd35ee1f16db3aaced2f98dbac045d102db go1.25.0.darwin-amd64.pkg +544932844156d8172f7a28f77f2ac9c15a23046698b6243f633b0a0b00c0749c go1.25.0.darwin-arm64.tar.gz +202a0d8338c152cb4c9f04782429e9ba8bef31d9889272380837e4043c9d800a go1.25.0.darwin-arm64.pkg +5ed3cf9a810a1483822538674f1336c06b51aa1b94d6d545a1a0319a48177120 go1.25.0.dragonfly-amd64.tar.gz +abea5d5c6697e6b5c224731f2158fe87c602996a2a233ac0c4730cd57bf8374e go1.25.0.freebsd-386.tar.gz +86e6fe0a29698d7601c4442052dac48bd58d532c51cccb8f1917df648138730b go1.25.0.freebsd-amd64.tar.gz +d90b78e41921f72f30e8bbc81d9dec2cff7ff384a33d8d8debb24053e4336bfe go1.25.0.freebsd-arm.tar.gz +451d0da1affd886bfb291b7c63a6018527b269505db21ce6e14724f22ab0662e go1.25.0.freebsd-arm64.tar.gz +7b565f76bd8bda46549eeaaefe0e53b251e644c230577290c0f66b1ecdb3cdbe go1.25.0.freebsd-riscv64.tar.gz +b1e1fdaab1ad25aa1c08d7a36c97d45d74b98b89c3f78c6d2145f77face54a2c go1.25.0.illumos-amd64.tar.gz +8c602dd9d99bc9453b3995d20ce4baf382cc50855900a0ece5de9929df4a993a go1.25.0.linux-386.tar.gz +2852af0cb20a13139b3448992e69b868e50ed0f8a1e5940ee1de9e19a123b613 go1.25.0.linux-amd64.tar.gz +05de75d6994a2783699815ee553bd5a9327d8b79991de36e38b66862782f54ae go1.25.0.linux-arm64.tar.gz +a5a8f8198fcf00e1e485b8ecef9ee020778bf32a408a4e8873371bfce458cd09 go1.25.0.linux-armv6l.tar.gz +cab86b1cf761b1cb3bac86a8877cfc92e7b036fc0d3084123d77013d61432afc go1.25.0.linux-loong64.tar.gz +d66b6fb74c3d91b9829dc95ec10ca1f047ef5e89332152f92e136cf0e2da5be1 go1.25.0.linux-mips.tar.gz +4082e4381a8661bc2a839ff94ba3daf4f6cde20f8fb771b5b3d4762dc84198a2 go1.25.0.linux-mips64.tar.gz +70002c299ec7f7175ac2ef673b1b347eecfa54ae11f34416a6053c17f855afcc go1.25.0.linux-mips64le.tar.gz +b00a3a39eff099f6df9f1c7355bf28e4589d0586f42d7d4a394efb763d145a73 go1.25.0.linux-mipsle.tar.gz +df166f33bd98160662560a72ff0b4ba731f969a80f088922bddcf566a88c1ec1 go1.25.0.linux-ppc64.tar.gz +0f18a89e7576cf2c5fa0b487a1635d9bcbf843df5f110e9982c64df52a983ad0 go1.25.0.linux-ppc64le.tar.gz +c018ff74a2c48d55c8ca9b07c8e24163558ffec8bea08b326d6336905d956b67 go1.25.0.linux-riscv64.tar.gz +34e5a2e19f2292fbaf8783e3a241e6e49689276aef6510a8060ea5ef54eee408 go1.25.0.linux-s390x.tar.gz +f8586cdb7aa855657609a5c5f6dbf523efa00c2bbd7c76d3936bec80aa6c0aba go1.25.0.netbsd-386.tar.gz +ae8dc1469385b86a157a423bb56304ba45730de8a897615874f57dd096db2c2a go1.25.0.netbsd-amd64.tar.gz +1ff7e4cc764425fc9dd6825eaee79d02b3c7cafffbb3691687c8d672ade76cb7 go1.25.0.netbsd-arm.tar.gz +e1b310739f26724216aa6d7d7208c4031f9ff54c9b5b9a796ddc8bebcb4a5f16 go1.25.0.netbsd-arm64.tar.gz +4802a9b20e533da91adb84aab42e94aa56cfe3e5475d0550bed3385b182e69d8 go1.25.0.openbsd-386.tar.gz +c016cd984bebe317b19a4f297c4f50def120dc9788490540c89f28e42f1dabe1 go1.25.0.openbsd-amd64.tar.gz +a1e31d0bf22172ddde42edf5ec811ef81be43433df0948ece52fecb247ccfd8d go1.25.0.openbsd-arm.tar.gz +343ea8edd8c218196e15a859c6072d0dd3246fbbb168481ab665eb4c4140458d go1.25.0.openbsd-arm64.tar.gz +694c14da1bcaeb5e3332d49bdc2b6d155067648f8fe1540c5de8f3cf8e157154 go1.25.0.openbsd-ppc64.tar.gz +aa510ad25cf54c06cd9c70b6d80ded69cb20188ac6e1735655eef29ff7e7885f go1.25.0.openbsd-riscv64.tar.gz +46f8cef02086cf04bf186c5912776b56535178d4cb319cd19c9fdbdd29231986 go1.25.0.plan9-386.tar.gz +29b34391d84095e44608a228f63f2f88113a37b74a79781353ec043dfbcb427b go1.25.0.plan9-amd64.tar.gz +0a047107d13ebe7943aaa6d54b1d7bbd2e45e68ce449b52915a818da715799c2 go1.25.0.plan9-arm.tar.gz +9977f9e4351984364a3b2b78f8b88bfd1d339812356d5237678514594b7d3611 go1.25.0.solaris-amd64.tar.gz +df9f39db82a803af0db639e3613a36681ab7a42866b1384b3f3a1045663961a7 go1.25.0.windows-386.zip +afd9e0a8d2665ff122c8302bb4a3ce4a5331e4e630ddc388be1f9238adfa8fe3 go1.25.0.windows-386.msi +89efb4f9b30812eee083cc1770fdd2913c14d301064f6454851428f9707d190b go1.25.0.windows-amd64.zip +936bd87109da515f79d80211de5bc6cbda071f2cc577f7e6af1a9e754ea34819 go1.25.0.windows-amd64.msi +27bab004c72b3d7bd05a69b6ec0fc54a309b4b78cc569dd963d8b3ec28bfdb8c go1.25.0.windows-arm64.zip +357d030b217ff68e700b6cfc56097bc21ad493bb45b79733a052d112f5031ed9 go1.25.0.windows-arm64.msi # version:golangci 2.0.2 # https://github.com/golangci/golangci-lint/releases/ From e798e26c69dde8405280de92dd076ca7dde254a3 Mon Sep 17 00:00:00 2001 From: cui Date: Thu, 14 Aug 2025 20:32:45 +0800 Subject: [PATCH 49/57] crypto/secp256k1: use ReadBits from common/math (#32430) --- crypto/secp256k1/curve.go | 25 +++---------------------- crypto/secp256k1/scalar_mult_cgo.go | 6 ++++-- 2 files changed, 7 insertions(+), 24 deletions(-) diff --git a/crypto/secp256k1/curve.go b/crypto/secp256k1/curve.go index 85ba885d6f..b82b147e3c 100644 --- a/crypto/secp256k1/curve.go +++ b/crypto/secp256k1/curve.go @@ -35,29 +35,10 @@ package secp256k1 import ( "crypto/elliptic" "math/big" -) -const ( - // number of bits in a big.Word - wordBits = 32 << (uint64(^big.Word(0)) >> 63) - // number of bytes in a big.Word - wordBytes = wordBits / 8 + "github.com/ethereum/go-ethereum/common/math" ) -// readBits encodes the absolute value of bigint as big-endian bytes. Callers -// must ensure that buf has enough space. If buf is too short the result will -// be incomplete. -func readBits(bigint *big.Int, buf []byte) { - i := len(buf) - for _, d := range bigint.Bits() { - for j := 0; j < wordBytes && i > 0; j++ { - i-- - buf[i] = byte(d) - d >>= 8 - } - } -} - // This code is from https://github.com/ThePiachu/GoBit and implements // several Koblitz elliptic curves over prime fields. // @@ -257,8 +238,8 @@ func (bitCurve *BitCurve) Marshal(x, y *big.Int) []byte { byteLen := (bitCurve.BitSize + 7) >> 3 ret := make([]byte, 1+2*byteLen) ret[0] = 4 // uncompressed point flag - readBits(x, ret[1:1+byteLen]) - readBits(y, ret[1+byteLen:]) + math.ReadBits(x, ret[1:1+byteLen]) + math.ReadBits(y, ret[1+byteLen:]) return ret } diff --git a/crypto/secp256k1/scalar_mult_cgo.go b/crypto/secp256k1/scalar_mult_cgo.go index d11c11faf8..b16c13f7e2 100644 --- a/crypto/secp256k1/scalar_mult_cgo.go +++ b/crypto/secp256k1/scalar_mult_cgo.go @@ -10,6 +10,8 @@ package secp256k1 import ( "math/big" "unsafe" + + "github.com/ethereum/go-ethereum/common/math" ) /* @@ -34,8 +36,8 @@ func (bitCurve *BitCurve) ScalarMult(Bx, By *big.Int, scalar []byte) (*big.Int, // Do the multiplication in C, updating point. point := make([]byte, 64) - readBits(Bx, point[:32]) - readBits(By, point[32:]) + math.ReadBits(Bx, point[:32]) + math.ReadBits(By, point[32:]) pointPtr := (*C.uchar)(unsafe.Pointer(&point[0])) scalarPtr := (*C.uchar)(unsafe.Pointer(&scalar[0])) From 2dbb580f51b61d7ff78fceb44b06835827704110 Mon Sep 17 00:00:00 2001 From: cui Date: Thu, 14 Aug 2025 20:47:43 +0800 Subject: [PATCH 50/57] build: remove unused functions (#32393) --- build/ci.go | 4 ---- internal/build/file.go | 17 ----------------- 2 files changed, 21 deletions(-) diff --git a/build/ci.go b/build/ci.go index 5126793c3d..df2b973a3a 100644 --- a/build/ci.go +++ b/build/ci.go @@ -343,10 +343,6 @@ func downloadSpecTestFixtures(csdb *download.ChecksumDB, cachedir string) string return filepath.Join(cachedir, base) } -// doCheckTidy assets that the Go modules files are tidied already. -func doCheckTidy() { -} - // doCheckGenerate ensures that re-generating generated files does not cause // any mutations in the source file tree. func doCheckGenerate() { diff --git a/internal/build/file.go b/internal/build/file.go index 2d8c993f36..7490af281e 100644 --- a/internal/build/file.go +++ b/internal/build/file.go @@ -34,23 +34,6 @@ func FileExist(path string) bool { return true } -// HashFiles iterates the provided set of files, computing the hash of each. -func HashFiles(files []string) (map[string][32]byte, error) { - res := make(map[string][32]byte) - for _, filePath := range files { - f, err := os.OpenFile(filePath, os.O_RDONLY, 0666) - if err != nil { - return nil, err - } - hasher := sha256.New() - if _, err := io.Copy(hasher, f); err != nil { - return nil, err - } - res[filePath] = [32]byte(hasher.Sum(nil)) - } - return res, nil -} - // HashFolder iterates all files under the given directory, computing the hash // of each. func HashFolder(folder string, exlude []string) (map[string][32]byte, error) { From ea3a71792da3c883d6806e350cf34d795a253913 Mon Sep 17 00:00:00 2001 From: Guillaume Ballet <3272758+gballet@users.noreply.github.com> Date: Fri, 15 Aug 2025 08:34:32 +0200 Subject: [PATCH 51/57] trie, core/state: add the transition tree (verkle transition part 2) (#32366) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This add some of the changes that were missing from #31634. It introduces the `TransitionTrie`, which is a façade pattern between the current MPT trie and the overlay tree. --------- Signed-off-by: Guillaume Ballet <3272758+gballet@users.noreply.github.com> Co-authored-by: rjl493456442 --- core/state/reader.go | 14 ++- trie/transition.go | 205 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 218 insertions(+), 1 deletion(-) create mode 100644 trie/transition.go diff --git a/core/state/reader.go b/core/state/reader.go index f56a1bfae1..4fc67ebd60 100644 --- a/core/state/reader.go +++ b/core/state/reader.go @@ -23,6 +23,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/lru" + "github.com/ethereum/go-ethereum/core/overlay" "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/crypto" @@ -241,8 +242,19 @@ func newTrieReader(root common.Hash, db *triedb.Database, cache *utils.PointCach if !db.IsVerkle() { tr, err = trie.NewStateTrie(trie.StateTrieID(root), db) } else { - // TODO @gballet determine the trie type (verkle or overlay) by transition state tr, err = trie.NewVerkleTrie(root, db, cache) + + // Based on the transition status, determine if the overlay + // tree needs to be created, or if a single, target tree is + // to be picked. + ts := overlay.LoadTransitionState(db.Disk(), root, true) + if ts.InTransition() { + mpt, err := trie.NewStateTrie(trie.StateTrieID(ts.BaseRoot), db) + if err != nil { + return nil, err + } + tr = trie.NewTransitionTree(mpt, tr.(*trie.VerkleTrie), false) + } } if err != nil { return nil, err diff --git a/trie/transition.go b/trie/transition.go new file mode 100644 index 0000000000..ad3f782b75 --- /dev/null +++ b/trie/transition.go @@ -0,0 +1,205 @@ +// Copyright 2025 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 ( + "fmt" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/ethdb" + "github.com/ethereum/go-ethereum/trie/trienode" + "github.com/ethereum/go-verkle" +) + +// TransitionTrie is a trie that implements a façade design pattern, presenting +// a single interface to the old MPT trie and the new verkle/binary trie. Reads +// first from the overlay trie, and falls back to the base trie if the key isn't +// found. All writes go to the overlay trie. +type TransitionTrie struct { + overlay *VerkleTrie + base *SecureTrie + storage bool +} + +// NewTransitionTrie creates a new TransitionTrie. +func NewTransitionTree(base *SecureTrie, overlay *VerkleTrie, st bool) *TransitionTrie { + return &TransitionTrie{ + overlay: overlay, + base: base, + storage: st, + } +} + +// Base returns the base trie. +func (t *TransitionTrie) Base() *SecureTrie { + return t.base +} + +// Overlay returns the overlay trie. +func (t *TransitionTrie) Overlay() *VerkleTrie { + return t.overlay +} + +// GetKey returns the sha3 preimage of a hashed key that was previously used +// to store a value. +func (t *TransitionTrie) GetKey(key []byte) []byte { + if key := t.overlay.GetKey(key); key != nil { + return key + } + return t.base.GetKey(key) +} + +// GetStorage returns the value for key stored in the trie. The value bytes must +// not be modified by the caller. +func (t *TransitionTrie) GetStorage(addr common.Address, key []byte) ([]byte, error) { + val, err := t.overlay.GetStorage(addr, key) + if err != nil { + return nil, fmt.Errorf("get storage from overlay: %s", err) + } + if len(val) != 0 { + return val, nil + } + // TODO also insert value into overlay + return t.base.GetStorage(addr, key) +} + +// GetAccount abstract an account read from the trie. +func (t *TransitionTrie) GetAccount(address common.Address) (*types.StateAccount, error) { + data, err := t.overlay.GetAccount(address) + if err != nil { + // Post cancun, no indicator needs to be used to indicate that + // an account was deleted in the overlay tree. If an error is + // returned, then it's a genuine error, and not an indicator + // that a tombstone was found. + return nil, err + } + if data != nil { + return data, nil + } + return t.base.GetAccount(address) +} + +// UpdateStorage associates key with value in the trie. If value has length zero, any +// existing value is deleted from the trie. The value bytes must not be modified +// by the caller while they are stored in the trie. +func (t *TransitionTrie) UpdateStorage(address common.Address, key []byte, value []byte) error { + var v []byte + if len(value) >= 32 { + v = value[:32] + } else { + var val [32]byte + copy(val[32-len(value):], value[:]) + v = val[:] + } + return t.overlay.UpdateStorage(address, key, v) +} + +// UpdateAccount abstract an account write to the trie. +func (t *TransitionTrie) UpdateAccount(addr common.Address, account *types.StateAccount, codeLen int) error { + // NOTE: before the rebase, this was saving the state root, so that OpenStorageTrie + // could still work during a replay. This is no longer needed, as OpenStorageTrie + // only needs to know what the account trie does now. + return t.overlay.UpdateAccount(addr, account, codeLen) +} + +// DeleteStorage removes any existing value for key from the trie. If a node was not +// found in the database, a trie.MissingNodeError is returned. +func (t *TransitionTrie) DeleteStorage(addr common.Address, key []byte) error { + return t.overlay.DeleteStorage(addr, key) +} + +// DeleteAccount abstracts an account deletion from the trie. +func (t *TransitionTrie) DeleteAccount(key common.Address) error { + return t.overlay.DeleteAccount(key) +} + +// Hash returns the root hash of the trie. It does not write to the database and +// can be used even if the trie doesn't have one. +func (t *TransitionTrie) Hash() common.Hash { + return t.overlay.Hash() +} + +// Commit collects all dirty nodes in the trie and replace them with the +// corresponding node hash. All collected nodes(including dirty leaves if +// collectLeaf is true) will be encapsulated into a nodeset for return. +// The returned nodeset can be nil if the trie is clean(nothing to commit). +// Once the trie is committed, it's not usable anymore. A new trie must +// be created with new root and updated trie database for following usage +func (t *TransitionTrie) Commit(collectLeaf bool) (common.Hash, *trienode.NodeSet) { + // Just return if the trie is a storage trie: otherwise, + // the overlay trie will be committed as many times as + // there are storage tries. This would kill performance. + if t.storage { + return common.Hash{}, nil + } + return t.overlay.Commit(collectLeaf) +} + +// NodeIterator returns an iterator that returns nodes of the trie. Iteration +// starts at the key after the given start key. +func (t *TransitionTrie) NodeIterator(startKey []byte) (NodeIterator, error) { + panic("not implemented") // TODO: Implement +} + +// Prove constructs a Merkle proof for key. The result contains all encoded nodes +// on the path to the value at key. The value itself is also included in the last +// node and can be retrieved by verifying the proof. +// +// If the trie does not contain a value for key, the returned proof contains all +// nodes of the longest existing prefix of the key (at least the root), ending +// with the node that proves the absence of the key. +func (t *TransitionTrie) Prove(key []byte, proofDb ethdb.KeyValueWriter) error { + panic("not implemented") // TODO: Implement +} + +// IsVerkle returns true if the trie is verkle-tree based +func (t *TransitionTrie) IsVerkle() bool { + // For all intents and purposes, the calling code should treat this as a verkle trie + return true +} + +// UpdateStems updates a group of values, given the stem they are using. If +// a value already exists, it is overwritten. +func (t *TransitionTrie) UpdateStem(key []byte, values [][]byte) error { + trie := t.overlay + switch root := trie.root.(type) { + case *verkle.InternalNode: + return root.InsertValuesAtStem(key, values, t.overlay.nodeResolver) + default: + panic("invalid root type") + } +} + +// Copy creates a deep copy of the transition trie. +func (t *TransitionTrie) Copy() *TransitionTrie { + return &TransitionTrie{ + overlay: t.overlay.Copy(), + base: t.base.Copy(), + storage: t.storage, + } +} + +// UpdateContractCode updates the contract code for the given address. +func (t *TransitionTrie) UpdateContractCode(addr common.Address, codeHash common.Hash, code []byte) error { + return t.overlay.UpdateContractCode(addr, codeHash, code) +} + +// Witness returns a set containing all trie nodes that have been accessed. +func (t *TransitionTrie) Witness() map[string]struct{} { + panic("not implemented") +} From a002a6c03f1990feebfa90da9d0e678a623c228f Mon Sep 17 00:00:00 2001 From: Guillaume Ballet <3272758+gballet@users.noreply.github.com> Date: Fri, 15 Aug 2025 08:58:24 +0200 Subject: [PATCH 52/57] cmd/evm: use PathScheme in blockrunner (#32444) This is a preparatory change for Verkle/binary trees, since they don't support the hash-based database scheme. This has no impact on the MPT. --- cmd/evm/blockrunner.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/evm/blockrunner.go b/cmd/evm/blockrunner.go index 31d1ba5ba1..f6538b1356 100644 --- a/cmd/evm/blockrunner.go +++ b/cmd/evm/blockrunner.go @@ -89,7 +89,7 @@ func runBlockTest(ctx *cli.Context, fname string) ([]testResult, error) { continue } result := &testResult{Name: name, Pass: true} - if err := tests[name].Run(false, rawdb.HashScheme, ctx.Bool(WitnessCrossCheckFlag.Name), tracer, func(res error, chain *core.BlockChain) { + if err := tests[name].Run(false, rawdb.PathScheme, ctx.Bool(WitnessCrossCheckFlag.Name), tracer, func(res error, chain *core.BlockChain) { if ctx.Bool(DumpFlag.Name) { if s, _ := chain.State(); s != nil { result.State = dump(s) From ccf684f1bae5cc542d49fb5b46e296b6e465d9ca Mon Sep 17 00:00:00 2001 From: cui Date: Fri, 15 Aug 2025 15:10:44 +0800 Subject: [PATCH 53/57] core/vm: refactor to use bitutil.TestBytes (#32434) --- core/vm/common.go | 9 --------- core/vm/contracts.go | 3 ++- 2 files changed, 2 insertions(+), 10 deletions(-) diff --git a/core/vm/common.go b/core/vm/common.go index 658803b820..2990f58972 100644 --- a/core/vm/common.go +++ b/core/vm/common.go @@ -84,12 +84,3 @@ func toWordSize(size uint64) uint64 { return (size + 31) / 32 } - -func allZero(b []byte) bool { - for _, byte := range b { - if byte != 0 { - return false - } - } - return true -} diff --git a/core/vm/contracts.go b/core/vm/contracts.go index 21307ff5ac..d286150277 100644 --- a/core/vm/contracts.go +++ b/core/vm/contracts.go @@ -30,6 +30,7 @@ import ( "github.com/consensys/gnark-crypto/ecc/bls12-381/fp" "github.com/consensys/gnark-crypto/ecc/bls12-381/fr" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/bitutil" "github.com/ethereum/go-ethereum/core/tracing" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/crypto/blake2b" @@ -289,7 +290,7 @@ func (c *ecrecover) Run(input []byte) ([]byte, error) { v := input[63] - 27 // tighter sig s values input homestead only apply to tx sigs - if !allZero(input[32:63]) || !crypto.ValidateSignatureValues(v, r, s, false) { + if bitutil.TestBytes(input[32:63]) || !crypto.ValidateSignatureValues(v, r, s, false) { return nil, nil } // We must make sure not to modify the 'input', so placing the 'v' along with From 88922d2bf5fc33b29ecc87b186d7d673264f1ef6 Mon Sep 17 00:00:00 2001 From: cui Date: Fri, 15 Aug 2025 15:12:22 +0800 Subject: [PATCH 54/57] crypto/bn256: refactor to use bitutil.TestBytes (#32435) --- crypto/bn256/gnark/g1.go | 12 ++---------- crypto/bn256/gnark/g2.go | 3 ++- 2 files changed, 4 insertions(+), 11 deletions(-) diff --git a/crypto/bn256/gnark/g1.go b/crypto/bn256/gnark/g1.go index 59e04cb247..bb758c3580 100644 --- a/crypto/bn256/gnark/g1.go +++ b/crypto/bn256/gnark/g1.go @@ -5,6 +5,7 @@ import ( "math/big" "github.com/consensys/gnark-crypto/ecc/bn254" + "github.com/ethereum/go-ethereum/common/bitutil" ) // G1 is the affine representation of a G1 group element. @@ -43,7 +44,7 @@ func (g *G1) Unmarshal(buf []byte) (int, error) { return 0, errors.New("invalid G1 point size") } - if allZeroes(buf[:64]) { + if !bitutil.TestBytes(buf[:64]) { // point at infinity g.inner.X.SetZero() g.inner.Y.SetZero() @@ -82,12 +83,3 @@ func (p *G1) Marshal() []byte { return output } - -func allZeroes(buf []byte) bool { - for i := range buf { - if buf[i] != 0 { - return false - } - } - return true -} diff --git a/crypto/bn256/gnark/g2.go b/crypto/bn256/gnark/g2.go index 48a797e5a7..87ad88b9f1 100644 --- a/crypto/bn256/gnark/g2.go +++ b/crypto/bn256/gnark/g2.go @@ -4,6 +4,7 @@ import ( "errors" "github.com/consensys/gnark-crypto/ecc/bn254" + "github.com/ethereum/go-ethereum/common/bitutil" ) // G2 is the affine representation of a G2 group element. @@ -31,7 +32,7 @@ func (g *G2) Unmarshal(buf []byte) (int, error) { return 0, errors.New("invalid G2 point size") } - if allZeroes(buf[:128]) { + if !bitutil.TestBytes(buf[:128]) { // point at infinity g.inner.X.A0.SetZero() g.inner.X.A1.SetZero() From 1d29e3ec0ed0afc7c2cc7ebe2b4b694cc5485b9a Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Fri, 15 Aug 2025 14:07:27 +0200 Subject: [PATCH 55/57] consensus/misc/eip4844: use blob parameters of current header (#32424) This changes the implementation to resolve the blob parameters according to the current header timestamp. This matters for EIP-7918, where we would previously resolve the UpdateFraction according to the parent header fork, leading to a confusing situation at the fork transition block. --------- Co-authored-by: MariusVanDerWijden --- consensus/misc/eip4844/eip4844.go | 190 +++++++++++++------------ consensus/misc/eip4844/eip4844_test.go | 65 ++++++++- 2 files changed, 161 insertions(+), 94 deletions(-) diff --git a/consensus/misc/eip4844/eip4844.go b/consensus/misc/eip4844/eip4844.go index fc143027dd..e14d129561 100644 --- a/consensus/misc/eip4844/eip4844.go +++ b/consensus/misc/eip4844/eip4844.go @@ -19,6 +19,7 @@ package eip4844 import ( "errors" "fmt" + "math" "math/big" "github.com/ethereum/go-ethereum/core/types" @@ -29,6 +30,66 @@ var ( minBlobGasPrice = big.NewInt(params.BlobTxMinBlobGasprice) ) +// BlobConfig contains the parameters for blob-related formulas. +// These can be adjusted in a fork. +type BlobConfig struct { + Target int + Max int + UpdateFraction uint64 +} + +func (bc *BlobConfig) maxBlobGas() uint64 { + return uint64(bc.Max) * params.BlobTxBlobGasPerBlob +} + +// blobBaseFee computes the blob fee. +func (bc *BlobConfig) blobBaseFee(excessBlobGas uint64) *big.Int { + return fakeExponential(minBlobGasPrice, new(big.Int).SetUint64(excessBlobGas), new(big.Int).SetUint64(bc.UpdateFraction)) +} + +// blobPrice returns the price of one blob in Wei. +func (bc *BlobConfig) blobPrice(excessBlobGas uint64) *big.Int { + f := bc.blobBaseFee(excessBlobGas) + return new(big.Int).Mul(f, big.NewInt(params.BlobTxBlobGasPerBlob)) +} + +func latestBlobConfig(cfg *params.ChainConfig, time uint64) *BlobConfig { + if cfg.BlobScheduleConfig == nil { + return nil + } + var ( + london = cfg.LondonBlock + s = cfg.BlobScheduleConfig + bc *params.BlobConfig + ) + switch { + case cfg.IsBPO5(london, time) && s.BPO5 != nil: + bc = s.BPO5 + case cfg.IsBPO4(london, time) && s.BPO4 != nil: + bc = s.BPO4 + case cfg.IsBPO3(london, time) && s.BPO3 != nil: + bc = s.BPO3 + case cfg.IsBPO2(london, time) && s.BPO2 != nil: + bc = s.BPO2 + case cfg.IsBPO1(london, time) && s.BPO1 != nil: + bc = s.BPO1 + case cfg.IsOsaka(london, time) && s.Osaka != nil: + bc = s.Osaka + case cfg.IsPrague(london, time) && s.Prague != nil: + bc = s.Prague + case cfg.IsCancun(london, time) && s.Cancun != nil: + bc = s.Cancun + default: + return nil + } + + return &BlobConfig{ + Target: bc.Target, + Max: bc.Max, + UpdateFraction: bc.UpdateFraction, + } +} + // VerifyEIP4844Header verifies the presence of the excessBlobGas field and that // if the current block contains no transactions, the excessBlobGas is updated // accordingly. @@ -36,21 +97,27 @@ func VerifyEIP4844Header(config *params.ChainConfig, parent, header *types.Heade if header.Number.Uint64() != parent.Number.Uint64()+1 { panic("bad header pair") } - // Verify the header is not malformed + + bcfg := latestBlobConfig(config, header.Time) + if bcfg == nil { + panic("called before EIP-4844 is active") + } + if header.ExcessBlobGas == nil { return errors.New("header is missing excessBlobGas") } if header.BlobGasUsed == nil { return errors.New("header is missing blobGasUsed") } + // Verify that the blob gas used remains within reasonable limits. - maxBlobGas := MaxBlobGasPerBlock(config, header.Time) - if *header.BlobGasUsed > maxBlobGas { - return fmt.Errorf("blob gas used %d exceeds maximum allowance %d", *header.BlobGasUsed, maxBlobGas) + if *header.BlobGasUsed > bcfg.maxBlobGas() { + return fmt.Errorf("blob gas used %d exceeds maximum allowance %d", *header.BlobGasUsed, bcfg.maxBlobGas()) } if *header.BlobGasUsed%params.BlobTxBlobGasPerBlob != 0 { return fmt.Errorf("blob gas used %d not a multiple of blob gas per blob %d", header.BlobGasUsed, params.BlobTxBlobGasPerBlob) } + // Verify the excessBlobGas is correct based on the parent header expectedExcessBlobGas := CalcExcessBlobGas(config, parent, header.Time) if *header.ExcessBlobGas != expectedExcessBlobGas { @@ -62,38 +129,41 @@ func VerifyEIP4844Header(config *params.ChainConfig, parent, header *types.Heade // CalcExcessBlobGas calculates the excess blob gas after applying the set of // blobs on top of the excess blob gas. func CalcExcessBlobGas(config *params.ChainConfig, parent *types.Header, headTimestamp uint64) uint64 { - var ( - parentExcessBlobGas uint64 - parentBlobGasUsed uint64 - ) + isOsaka := config.IsOsaka(config.LondonBlock, headTimestamp) + bcfg := latestBlobConfig(config, headTimestamp) + return calcExcessBlobGas(isOsaka, bcfg, parent) +} + +func calcExcessBlobGas(isOsaka bool, bcfg *BlobConfig, parent *types.Header) uint64 { + var parentExcessBlobGas, parentBlobGasUsed uint64 if parent.ExcessBlobGas != nil { parentExcessBlobGas = *parent.ExcessBlobGas parentBlobGasUsed = *parent.BlobGasUsed } + var ( excessBlobGas = parentExcessBlobGas + parentBlobGasUsed - target = targetBlobsPerBlock(config, headTimestamp) - targetGas = uint64(target) * params.BlobTxBlobGasPerBlob + targetGas = uint64(bcfg.Target) * params.BlobTxBlobGasPerBlob ) if excessBlobGas < targetGas { return 0 } - if !config.IsOsaka(config.LondonBlock, headTimestamp) { - // Pre-Osaka, we use the formula defined by EIP-4844. - return excessBlobGas - targetGas + + // EIP-7918 (post-Osaka) introduces a different formula for computing excess, + // in cases where the price is lower than a 'reserve price'. + if isOsaka { + var ( + baseCost = big.NewInt(params.BlobBaseCost) + reservePrice = baseCost.Mul(baseCost, parent.BaseFee) + blobPrice = bcfg.blobPrice(parentExcessBlobGas) + ) + if reservePrice.Cmp(blobPrice) > 0 { + scaledExcess := parentBlobGasUsed * uint64(bcfg.Max-bcfg.Target) / uint64(bcfg.Max) + return parentExcessBlobGas + scaledExcess + } } - // EIP-7918 (post-Osaka) introduces a different formula for computing excess. - var ( - baseCost = big.NewInt(params.BlobBaseCost) - reservePrice = baseCost.Mul(baseCost, parent.BaseFee) - blobPrice = calcBlobPrice(config, parent) - ) - if reservePrice.Cmp(blobPrice) > 0 { - max := MaxBlobsPerBlock(config, headTimestamp) - scaledExcess := parentBlobGasUsed * uint64(max-target) / uint64(max) - return parentExcessBlobGas + scaledExcess - } + // Original EIP-4844 formula. return excessBlobGas - targetGas } @@ -103,7 +173,7 @@ func CalcBlobFee(config *params.ChainConfig, header *types.Header) *big.Int { if blobConfig == nil { panic("calculating blob fee on unsupported fork") } - return fakeExponential(minBlobGasPrice, new(big.Int).SetUint64(*header.ExcessBlobGas), new(big.Int).SetUint64(blobConfig.UpdateFraction)) + return blobConfig.blobBaseFee(*header.ExcessBlobGas) } // MaxBlobsPerBlock returns the max blobs per block for a block at the given timestamp. @@ -115,36 +185,6 @@ func MaxBlobsPerBlock(cfg *params.ChainConfig, time uint64) int { return blobConfig.Max } -func latestBlobConfig(cfg *params.ChainConfig, time uint64) *params.BlobConfig { - if cfg.BlobScheduleConfig == nil { - return nil - } - var ( - london = cfg.LondonBlock - s = cfg.BlobScheduleConfig - ) - switch { - case cfg.IsBPO5(london, time) && s.BPO5 != nil: - return s.BPO5 - case cfg.IsBPO4(london, time) && s.BPO4 != nil: - return s.BPO4 - case cfg.IsBPO3(london, time) && s.BPO3 != nil: - return s.BPO3 - case cfg.IsBPO2(london, time) && s.BPO2 != nil: - return s.BPO2 - case cfg.IsBPO1(london, time) && s.BPO1 != nil: - return s.BPO1 - case cfg.IsOsaka(london, time) && s.Osaka != nil: - return s.Osaka - case cfg.IsPrague(london, time) && s.Prague != nil: - return s.Prague - case cfg.IsCancun(london, time) && s.Cancun != nil: - return s.Cancun - default: - return nil - } -} - // MaxBlobGasPerBlock returns the maximum blob gas that can be spent in a block at the given timestamp. func MaxBlobGasPerBlock(cfg *params.ChainConfig, time uint64) uint64 { return uint64(MaxBlobsPerBlock(cfg, time)) * params.BlobTxBlobGasPerBlob @@ -153,39 +193,11 @@ func MaxBlobGasPerBlock(cfg *params.ChainConfig, time uint64) uint64 { // LatestMaxBlobsPerBlock returns the latest max blobs per block defined by the // configuration, regardless of the currently active fork. func LatestMaxBlobsPerBlock(cfg *params.ChainConfig) int { - s := cfg.BlobScheduleConfig - if s == nil { + bcfg := latestBlobConfig(cfg, math.MaxUint64) + if bcfg == nil { return 0 } - switch { - case s.BPO5 != nil: - return s.BPO5.Max - case s.BPO4 != nil: - return s.BPO4.Max - case s.BPO3 != nil: - return s.BPO3.Max - case s.BPO2 != nil: - return s.BPO2.Max - case s.BPO1 != nil: - return s.BPO1.Max - case s.Osaka != nil: - return s.Osaka.Max - case s.Prague != nil: - return s.Prague.Max - case s.Cancun != nil: - return s.Cancun.Max - default: - return 0 - } -} - -// targetBlobsPerBlock returns the target number of blobs in a block at the given timestamp. -func targetBlobsPerBlock(cfg *params.ChainConfig, time uint64) int { - blobConfig := latestBlobConfig(cfg, time) - if blobConfig == nil { - return 0 - } - return blobConfig.Target + return bcfg.Max } // fakeExponential approximates factor * e ** (numerator / denominator) using @@ -204,9 +216,3 @@ func fakeExponential(factor, numerator, denominator *big.Int) *big.Int { } return output.Div(output, denominator) } - -// calcBlobPrice calculates the blob price for a block. -func calcBlobPrice(config *params.ChainConfig, header *types.Header) *big.Int { - blobBaseFee := CalcBlobFee(config, header) - return new(big.Int).Mul(blobBaseFee, big.NewInt(params.BlobTxBlobGasPerBlob)) -} diff --git a/consensus/misc/eip4844/eip4844_test.go b/consensus/misc/eip4844/eip4844_test.go index 555324db65..35934370af 100644 --- a/consensus/misc/eip4844/eip4844_test.go +++ b/consensus/misc/eip4844/eip4844_test.go @@ -28,9 +28,10 @@ import ( func TestCalcExcessBlobGas(t *testing.T) { var ( config = params.MainnetChainConfig - targetBlobs = targetBlobsPerBlock(config, *config.CancunTime) + targetBlobs = config.BlobScheduleConfig.Cancun.Target targetBlobGas = uint64(targetBlobs) * params.BlobTxBlobGasPerBlob ) + var tests = []struct { excess uint64 blobs int @@ -90,6 +91,65 @@ func TestCalcBlobFee(t *testing.T) { } } +func TestCalcBlobFeePostOsaka(t *testing.T) { + zero := uint64(0) + bpo1 := uint64(1754836608) + bpo2 := uint64(1754934912) + bpo3 := uint64(1755033216) + + tests := []struct { + excessBlobGas uint64 + blobGasUsed uint64 + blobfee uint64 + basefee uint64 + parenttime uint64 + headertime uint64 + }{ + {5149252, 1310720, 5617366, 30, 1754904516, 1754904528}, + {19251039, 2490368, 20107103, 50, 1755033204, 1755033216}, + } + for i, tt := range tests { + config := ¶ms.ChainConfig{ + LondonBlock: big.NewInt(0), + CancunTime: &zero, + PragueTime: &zero, + OsakaTime: &zero, + BPO1Time: &bpo1, + BPO2Time: &bpo2, + BPO3Time: &bpo3, + BlobScheduleConfig: ¶ms.BlobScheduleConfig{ + Cancun: params.DefaultCancunBlobConfig, + Prague: params.DefaultPragueBlobConfig, + Osaka: params.DefaultOsakaBlobConfig, + BPO1: ¶ms.BlobConfig{ + Target: 9, + Max: 14, + UpdateFraction: 8832827, + }, + BPO2: ¶ms.BlobConfig{ + Target: 14, + Max: 21, + UpdateFraction: 13739630, + }, + BPO3: ¶ms.BlobConfig{ + Target: 21, + Max: 32, + UpdateFraction: 20609697, + }, + }} + parent := &types.Header{ + ExcessBlobGas: &tt.excessBlobGas, + BlobGasUsed: &tt.blobGasUsed, + BaseFee: big.NewInt(int64(tt.basefee)), + Time: tt.parenttime, + } + have := CalcExcessBlobGas(config, parent, tt.headertime) + if have != tt.blobfee { + t.Errorf("test %d: blobfee mismatch: have %v want %v", i, have, tt.blobfee) + } + } +} + func TestFakeExponential(t *testing.T) { tests := []struct { factor int64 @@ -131,9 +191,10 @@ func TestFakeExponential(t *testing.T) { func TestCalcExcessBlobGasEIP7918(t *testing.T) { var ( cfg = params.MergedTestChainConfig - targetBlobs = targetBlobsPerBlock(cfg, *cfg.CancunTime) + targetBlobs = cfg.BlobScheduleConfig.Osaka.Target blobGasTarget = uint64(targetBlobs) * params.BlobTxBlobGasPerBlob ) + makeHeader := func(parentExcess, parentBaseFee uint64, blobsUsed int) *types.Header { blobGasUsed := uint64(blobsUsed) * params.BlobTxBlobGasPerBlob return &types.Header{ From 1693a48f8cf227f77c66457261a5a53938221ce7 Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Fri, 15 Aug 2025 14:08:27 +0200 Subject: [PATCH 56/57] rlp: remove workaround for Value.Bytes (#32433) As of Go 1.19, it is permitted to call Bytes() on a reflect.Value representing an adressable byte array. So we can remove our workaround, undoing #22924. https://go.dev/doc/go1.19#reflectpkgreflect > The method [Value.Bytes](https://go.dev/pkg/reflect/#Value.Bytes) now accepts addressable arrays in addition to slices. --- rlp/decode.go | 2 +- rlp/encode.go | 3 +-- rlp/safe.go | 27 --------------------------- rlp/unsafe.go | 30 ------------------------------ 4 files changed, 2 insertions(+), 60 deletions(-) delete mode 100644 rlp/safe.go delete mode 100644 rlp/unsafe.go diff --git a/rlp/decode.go b/rlp/decode.go index 5a06f35ec0..19074072fb 100644 --- a/rlp/decode.go +++ b/rlp/decode.go @@ -371,7 +371,7 @@ func decodeByteArray(s *Stream, val reflect.Value) error { if err != nil { return err } - slice := byteArrayBytes(val, val.Len()) + slice := val.Bytes() switch kind { case Byte: if len(slice) == 0 { diff --git a/rlp/encode.go b/rlp/encode.go index de2b02f629..ed99275739 100644 --- a/rlp/encode.go +++ b/rlp/encode.go @@ -240,7 +240,6 @@ func makeByteArrayWriter(typ reflect.Type) writer { case 1: return writeLengthOneByteArray default: - length := typ.Len() return func(val reflect.Value, w *encBuffer) error { if !val.CanAddr() { // Getting the byte slice of val requires it to be addressable. Make it @@ -249,7 +248,7 @@ func makeByteArrayWriter(typ reflect.Type) writer { copy.Set(val) val = copy } - slice := byteArrayBytes(val, length) + slice := val.Bytes() w.encodeStringHeader(len(slice)) w.str = append(w.str, slice...) return nil diff --git a/rlp/safe.go b/rlp/safe.go deleted file mode 100644 index 3c910337b6..0000000000 --- a/rlp/safe.go +++ /dev/null @@ -1,27 +0,0 @@ -// Copyright 2021 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 . - -//go:build nacl || js || !cgo -// +build nacl js !cgo - -package rlp - -import "reflect" - -// byteArrayBytes returns a slice of the byte array v. -func byteArrayBytes(v reflect.Value, length int) []byte { - return v.Slice(0, length).Bytes() -} diff --git a/rlp/unsafe.go b/rlp/unsafe.go deleted file mode 100644 index 10868caaf2..0000000000 --- a/rlp/unsafe.go +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright 2021 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 . - -//go:build !nacl && !js && cgo -// +build !nacl,!js,cgo - -package rlp - -import ( - "reflect" - "unsafe" -) - -// byteArrayBytes returns a slice of the byte array v. -func byteArrayBytes(v reflect.Value, length int) []byte { - return unsafe.Slice((*byte)(unsafe.Pointer(v.UnsafeAddr())), length) -} From a9a19c4202161347559d30f295fc268e18a4a089 Mon Sep 17 00:00:00 2001 From: jwasinger Date: Fri, 15 Aug 2025 22:58:00 +0900 Subject: [PATCH 57/57] core/vm: fix EIP-7823 modexp input length check (#32363) The order of the checks was wrong which would have allowed a call to modexp with `baseLen == 0 && modLen == 0` post fusaka. Also handles an edge case where base/mod/exp length >= 2**64 --------- Co-authored-by: Felix Lange --- core/vm/contracts.go | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/core/vm/contracts.go b/core/vm/contracts.go index d286150277..e9b80280bf 100644 --- a/core/vm/contracts.go +++ b/core/vm/contracts.go @@ -501,23 +501,28 @@ func (c *bigModExp) RequiredGas(input []byte) uint64 { func (c *bigModExp) Run(input []byte) ([]byte, error) { var ( - baseLen = new(big.Int).SetBytes(getData(input, 0, 32)).Uint64() - expLen = new(big.Int).SetBytes(getData(input, 32, 32)).Uint64() - modLen = new(big.Int).SetBytes(getData(input, 64, 32)).Uint64() + baseLenBig = new(big.Int).SetBytes(getData(input, 0, 32)) + expLenBig = new(big.Int).SetBytes(getData(input, 32, 32)) + modLenBig = new(big.Int).SetBytes(getData(input, 64, 32)) + baseLen = baseLenBig.Uint64() + expLen = expLenBig.Uint64() + modLen = modLenBig.Uint64() + inputLenOverflow = max(baseLenBig.BitLen(), expLenBig.BitLen(), modLenBig.BitLen()) > 64 ) if len(input) > 96 { input = input[96:] } else { input = input[:0] } + + // enforce size cap for inputs + if c.eip7823 && (inputLenOverflow || max(baseLen, expLen, modLen) > 1024) { + return nil, errors.New("one or more of base/exponent/modulus length exceeded 1024 bytes") + } // Handle a special case when both the base and mod length is zero if baseLen == 0 && modLen == 0 { return []byte{}, nil } - // enforce size cap for inputs - if c.eip7823 && max(baseLen, expLen, modLen) > 1024 { - return nil, errors.New("one or more of base/exponent/modulus length exceeded 1024 bytes") - } // Retrieve the operands and execute the exponentiation var ( base = new(big.Int).SetBytes(getData(input, 0, baseLen))