diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS
index 900ff52e52..4bc13aff92 100644
--- a/.github/CODEOWNERS
+++ b/.github/CODEOWNERS
@@ -19,7 +19,7 @@ eth/tracers/ @s1na
ethclient/ @fjl
ethdb/ @rjl493456442
event/ @fjl
-trie/ @rjl493456442
+trie/ @rjl493456442 @gballet
triedb/ @rjl493456442
core/tracing/ @s1na
graphql/ @s1na
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:
diff --git a/.github/workflows/validate_pr.yml b/.github/workflows/validate_pr.yml
new file mode 100644
index 0000000000..8c9ae1688f
--- /dev/null
+++ b/.github/workflows/validate_pr.yml
@@ -0,0 +1,23 @@
+name: PR Format Validation
+
+on:
+ pull_request:
+ types: [opened, edited, synchronize]
+
+jobs:
+ validate-pr:
+ runs-on: ubuntu-latest
+ steps:
+ - name: Check PR Title Format
+ uses: actions/github-script@v7
+ with:
+ script: |
+ const prTitle = context.payload.pull_request.title;
+ const titleRegex = /^(\.?[\w\s,{}/]+): .+/;
+
+ if (!titleRegex.test(prTitle)) {
+ core.setFailed(`PR title "${prTitle}" does not match required format: directory, ...: description`);
+ return;
+ }
+
+ console.log('✅ PR title format is valid');
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"
diff --git a/accounts/scwallet/wallet.go b/accounts/scwallet/wallet.go
index 58cfc88301..7612953c22 100644
--- a/accounts/scwallet/wallet.go
+++ b/accounts/scwallet/wallet.go
@@ -472,6 +472,11 @@ func (w *Wallet) selfDerive() {
continue
}
pairing := w.Hub.pairing(w)
+ if pairing == nil {
+ w.lock.Unlock()
+ reqc <- struct{}{}
+ continue
+ }
// Device lock obtained, derive the next batch of accounts
var (
@@ -631,13 +636,13 @@ func (w *Wallet) Derive(path accounts.DerivationPath, pin bool) (accounts.Accoun
}
if pin {
- pairing := w.Hub.pairing(w)
- pairing.Accounts[account.Address] = path
- if err := w.Hub.setPairing(w, pairing); err != nil {
- return accounts.Account{}, err
+ if pairing := w.Hub.pairing(w); pairing != nil {
+ pairing.Accounts[account.Address] = path
+ if err := w.Hub.setPairing(w, pairing); err != nil {
+ return accounts.Account{}, err
+ }
}
}
-
return account, nil
}
@@ -774,11 +779,11 @@ func (w *Wallet) SignTxWithPassphrase(account accounts.Account, passphrase strin
// It first checks for the address in the list of pinned accounts, and if it is
// not found, attempts to parse the derivation path from the account's URL.
func (w *Wallet) findAccountPath(account accounts.Account) (accounts.DerivationPath, error) {
- pairing := w.Hub.pairing(w)
- if path, ok := pairing.Accounts[account.Address]; ok {
- return path, nil
+ if pairing := w.Hub.pairing(w); pairing != nil {
+ if path, ok := pairing.Accounts[account.Address]; ok {
+ return path, nil
+ }
}
-
// Look for the path in the URL
if account.URL.Scheme != w.Hub.scheme {
return nil, fmt.Errorf("scheme %s does not match wallet scheme %s", account.URL.Scheme, w.Hub.scheme)
diff --git a/accounts/usbwallet/ledger.go b/accounts/usbwallet/ledger.go
index 2be6edd44f..52595a1621 100644
--- a/accounts/usbwallet/ledger.go
+++ b/accounts/usbwallet/ledger.go
@@ -166,7 +166,7 @@ func (w *ledgerDriver) SignTx(path accounts.DerivationPath, tx *types.Transactio
return common.Address{}, nil, accounts.ErrWalletClosed
}
// Ensure the wallet is capable of signing the given transaction
- if chainID != nil && w.version[0] <= 1 && w.version[1] <= 0 && w.version[2] <= 2 {
+ if chainID != nil && (w.version[0] < 1 || (w.version[0] == 1 && w.version[1] == 0 && w.version[2] < 3)) {
//lint:ignore ST1005 brand name displayed on the console
return common.Address{}, nil, fmt.Errorf("Ledger v%d.%d.%d doesn't support signing this transaction, please update to v1.0.3 at least", w.version[0], w.version[1], w.version[2])
}
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 {
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/
diff --git a/build/ci.go b/build/ci.go
index 5126793c3d..3856f32925 100644
--- a/build/ci.go
+++ b/build/ci.go
@@ -124,6 +124,7 @@ var (
"jammy", // 22.04, EOL: 04/2032
"noble", // 24.04, EOL: 04/2034
"oracular", // 24.10, EOL: 07/2025
+ "plucky", // 25.04, EOL: 01/2026
}
// This is where the tests should be unpacked.
@@ -343,10 +344,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/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)
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
diff --git a/cmd/workload/filtertestperf.go b/cmd/workload/filtertestperf.go
index c7d2fdd02a..d4f1a155f1 100644
--- a/cmd/workload/filtertestperf.go
+++ b/cmd/workload/filtertestperf.go
@@ -152,7 +152,7 @@ func (st *bucketStats) print(name string) {
name, st.count, float64(st.blocks)/float64(st.count), float64(st.logs)/float64(st.count), st.runtime/time.Duration(st.count))
}
-// writeQueries serializes the generated errors to the error file.
+// writeErrors serializes the generated errors to the error file.
func writeErrors(errorFile string, errors []*filterQuery) {
file, err := os.Create(errorFile)
if err != nil {
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)
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{
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)
diff --git a/core/blockchain.go b/core/blockchain.go
index 0b92a94b6c..5205483af9 100644
--- a/core/blockchain.go
+++ b/core/blockchain.go
@@ -2011,7 +2011,10 @@ func (bc *BlockChain) processBlock(parentRoot common.Hash, block *types.Block, s
// If we are past Byzantium, enable prefetching to pull in trie node paths
// while processing transactions. Before Byzantium the prefetcher is mostly
// useless due to the intermediate root hashing after each transaction.
- var witness *stateless.Witness
+ var (
+ witness *stateless.Witness
+ witnessStats *stateless.WitnessStats
+ )
if bc.chainConfig.IsByzantium(block.Number()) {
// Generate witnesses either if we're self-testing, or if it's the
// only block being inserted. A bit crude, but witnesses are huge,
@@ -2021,8 +2024,11 @@ func (bc *BlockChain) processBlock(parentRoot common.Hash, block *types.Block, s
if err != nil {
return nil, err
}
+ if bc.cfg.VmConfig.EnableWitnessStats {
+ witnessStats = stateless.NewWitnessStats()
+ }
}
- statedb.StartPrefetcher("chain", witness)
+ statedb.StartPrefetcher("chain", witness, witnessStats)
defer statedb.StopPrefetcher()
}
@@ -2083,6 +2089,7 @@ func (bc *BlockChain) processBlock(parentRoot common.Hash, block *types.Block, s
return nil, fmt.Errorf("stateless self-validation receipt root mismatch (cross: %x local: %x)", crossReceiptRoot, block.ReceiptHash())
}
}
+
xvtime := time.Since(xvstart)
proctime := time.Since(startTime) // processing + validation + cross validation
@@ -2118,6 +2125,11 @@ func (bc *BlockChain) processBlock(parentRoot common.Hash, block *types.Block, s
if err != nil {
return nil, err
}
+ // Report the collected witness statistics
+ if witnessStats != nil {
+ witnessStats.ReportMetrics()
+ }
+
// Update the metrics touched during block commit
accountCommitTimer.Update(statedb.AccountCommits) // Account commits are complete, we can mark them
storageCommitTimer.Update(statedb.StorageCommits) // Storage commits are complete, we can mark them
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/rawdb/database.go b/core/rawdb/database.go
index 25cd20d164..6a1b717066 100644
--- a/core/rawdb/database.go
+++ b/core/rawdb/database.go
@@ -32,7 +32,6 @@ import (
"github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/ethdb/memorydb"
"github.com/ethereum/go-ethereum/log"
- "github.com/olekukonko/tablewriter"
)
var ErrDeleteRangeInterrupted = errors.New("safe delete range operation interrupted")
@@ -582,7 +581,7 @@ func InspectDatabase(db ethdb.Database, keyPrefix, keyStart []byte) error {
}
total += ancient.size()
}
- table := tablewriter.NewWriter(os.Stdout)
+ table := newTableWriter(os.Stdout)
table.SetHeader([]string{"Database", "Category", "Size", "Items"})
table.SetFooter([]string{"", "Total", total.String(), " "})
table.AppendBulk(stats)
diff --git a/core/rawdb/database_tablewriter_tinygo.go b/core/rawdb/database_tablewriter_tinygo.go
new file mode 100644
index 0000000000..2f8e456fd5
--- /dev/null
+++ b/core/rawdb/database_tablewriter_tinygo.go
@@ -0,0 +1,208 @@
+// 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 .
+
+// TODO: naive stub implementation for tablewriter
+
+//go:build tinygo
+// +build tinygo
+
+package rawdb
+
+import (
+ "errors"
+ "fmt"
+ "io"
+ "strings"
+)
+
+const (
+ cellPadding = 1 // Number of spaces on each side of cell content
+ totalPadding = 2 * cellPadding // Total padding per cell. Its two because we pad equally on both sides
+)
+
+type Table struct {
+ out io.Writer
+ headers []string
+ footer []string
+ rows [][]string
+}
+
+func newTableWriter(w io.Writer) *Table {
+ return &Table{out: w}
+}
+
+// SetHeader sets the header row for the table. Headers define the column names
+// and determine the number of columns for the entire table.
+//
+// All data rows and footer must have the same number of columns as the headers.
+//
+// Note: Headers are required - tables without headers will fail validation.
+func (t *Table) SetHeader(headers []string) {
+ t.headers = headers
+}
+
+// SetFooter sets an optional footer row for the table.
+//
+// The footer must have the same number of columns as the headers, or validation will fail.
+func (t *Table) SetFooter(footer []string) {
+ t.footer = footer
+}
+
+// AppendBulk sets all data rows for the table at once, replacing any existing rows.
+//
+// Each row must have the same number of columns as the headers, or validation
+// will fail during Render().
+func (t *Table) AppendBulk(rows [][]string) {
+ t.rows = rows
+}
+
+// Render outputs the complete table to the configured writer. The table is rendered
+// with headers, data rows, and optional footer.
+//
+// If validation fails, an error message is written to the output and rendering stops.
+func (t *Table) Render() {
+ if err := t.render(); err != nil {
+ fmt.Fprintf(t.out, "Error: %v\n", err)
+ return
+ }
+}
+
+func (t *Table) render() error {
+ if err := t.validateColumnCount(); err != nil {
+ return err
+ }
+
+ widths := t.calculateColumnWidths()
+ rowSeparator := t.buildRowSeparator(widths)
+
+ if len(t.headers) > 0 {
+ t.printRow(t.headers, widths)
+ fmt.Fprintln(t.out, rowSeparator)
+ }
+
+ for _, row := range t.rows {
+ t.printRow(row, widths)
+ }
+
+ if len(t.footer) > 0 {
+ fmt.Fprintln(t.out, rowSeparator)
+ t.printRow(t.footer, widths)
+ }
+
+ return nil
+}
+
+// validateColumnCount checks that all rows and footer match the header column count
+func (t *Table) validateColumnCount() error {
+ if len(t.headers) == 0 {
+ return errors.New("table must have headers")
+ }
+
+ expectedCols := len(t.headers)
+
+ // Check all rows have same column count as headers
+ for i, row := range t.rows {
+ if len(row) != expectedCols {
+ return fmt.Errorf("row %d has %d columns, expected %d", i, len(row), expectedCols)
+ }
+ }
+
+ // Check footer has same column count as headers (if present)
+ footerPresent := len(t.footer) > 0
+ if footerPresent && len(t.footer) != expectedCols {
+ return fmt.Errorf("footer has %d columns, expected %d", len(t.footer), expectedCols)
+ }
+
+ return nil
+}
+
+// calculateColumnWidths determines the minimum width needed for each column.
+//
+// This is done by finding the longest content in each column across headers, rows, and footer.
+//
+// Returns an int slice where widths[i] is the display width for column i (including padding).
+func (t *Table) calculateColumnWidths() []int {
+ // Headers define the number of columns
+ cols := len(t.headers)
+ if cols == 0 {
+ return nil
+ }
+
+ // Track maximum content width for each column (before padding)
+ widths := make([]int, cols)
+
+ // Start with header widths
+ for i, h := range t.headers {
+ widths[i] = len(h)
+ }
+
+ // Find max width needed for data cells in each column
+ for _, row := range t.rows {
+ for i, cell := range row {
+ widths[i] = max(widths[i], len(cell))
+ }
+ }
+
+ // Find max width needed for footer in each column
+ for i, f := range t.footer {
+ widths[i] = max(widths[i], len(f))
+ }
+
+ for i := range widths {
+ widths[i] += totalPadding
+ }
+
+ return widths
+}
+
+// buildRowSeparator creates a horizontal line to separate table rows.
+//
+// It generates a string with dashes (-) for each column width, joined by plus signs (+).
+//
+// Example output: "----------+--------+-----------"
+func (t *Table) buildRowSeparator(widths []int) string {
+ parts := make([]string, len(widths))
+ for i, w := range widths {
+ parts[i] = strings.Repeat("-", w)
+ }
+ return strings.Join(parts, "+")
+}
+
+// printRow outputs a single row to the table writer.
+//
+// Each cell is padded with spaces and separated by pipe characters (|).
+//
+// Example output: " Database | Size | Items "
+func (t *Table) printRow(row []string, widths []int) {
+ for i, cell := range row {
+ if i > 0 {
+ fmt.Fprint(t.out, "|")
+ }
+
+ // Calculate centering pad without padding
+ contentWidth := widths[i] - totalPadding
+ cellLen := len(cell)
+ leftPadCentering := (contentWidth - cellLen) / 2
+ rightPadCentering := contentWidth - cellLen - leftPadCentering
+
+ // Build padded cell with centering
+ leftPadding := strings.Repeat(" ", cellPadding+leftPadCentering)
+ rightPadding := strings.Repeat(" ", cellPadding+rightPadCentering)
+
+ fmt.Fprintf(t.out, "%s%s%s", leftPadding, cell, rightPadding)
+ }
+ fmt.Fprintln(t.out)
+}
diff --git a/core/rawdb/database_tablewriter_tinygo_test.go b/core/rawdb/database_tablewriter_tinygo_test.go
new file mode 100644
index 0000000000..3bcf93832b
--- /dev/null
+++ b/core/rawdb/database_tablewriter_tinygo_test.go
@@ -0,0 +1,124 @@
+// 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 .
+
+//go:build tinygo
+// +build tinygo
+
+package rawdb
+
+import (
+ "bytes"
+ "strings"
+ "testing"
+)
+
+func TestTableWriterTinyGo(t *testing.T) {
+ var buf bytes.Buffer
+ table := newTableWriter(&buf)
+
+ headers := []string{"Database", "Size", "Items", "Status"}
+ rows := [][]string{
+ {"chaindata", "2.5 GB", "1,234,567", "Active"},
+ {"state", "890 MB", "456,789", "Active"},
+ {"ancient", "15.2 GB", "2,345,678", "Readonly"},
+ {"logs", "120 MB", "89,012", "Active"},
+ }
+ footer := []string{"Total", "18.71 GB", "4,125,046", "-"}
+
+ table.SetHeader(headers)
+ table.AppendBulk(rows)
+ table.SetFooter(footer)
+ table.Render()
+
+ output := buf.String()
+ t.Logf("Table output using custom stub implementation:\n%s", output)
+}
+
+func TestTableWriterValidationErrors(t *testing.T) {
+ // Test missing headers
+ t.Run("MissingHeaders", func(t *testing.T) {
+ var buf bytes.Buffer
+ table := newTableWriter(&buf)
+
+ rows := [][]string{{"x", "y", "z"}}
+
+ table.AppendBulk(rows)
+ table.Render()
+
+ output := buf.String()
+ if !strings.Contains(output, "table must have headers") {
+ t.Errorf("Expected error for missing headers, got: %s", output)
+ }
+ })
+
+ t.Run("NotEnoughRowColumns", func(t *testing.T) {
+ var buf bytes.Buffer
+ table := newTableWriter(&buf)
+
+ headers := []string{"A", "B", "C"}
+ badRows := [][]string{
+ {"x", "y"}, // Missing column
+ }
+
+ table.SetHeader(headers)
+ table.AppendBulk(badRows)
+ table.Render()
+
+ output := buf.String()
+ if !strings.Contains(output, "row 0 has 2 columns, expected 3") {
+ t.Errorf("Expected validation error for row 0, got: %s", output)
+ }
+ })
+
+ t.Run("TooManyRowColumns", func(t *testing.T) {
+ var buf bytes.Buffer
+ table := newTableWriter(&buf)
+
+ headers := []string{"A", "B", "C"}
+ badRows := [][]string{
+ {"p", "q", "r", "s"}, // Extra column
+ }
+
+ table.SetHeader(headers)
+ table.AppendBulk(badRows)
+ table.Render()
+
+ output := buf.String()
+ if !strings.Contains(output, "row 0 has 4 columns, expected 3") {
+ t.Errorf("Expected validation error for row 0, got: %s", output)
+ }
+ })
+
+ // Test mismatched footer columns
+ t.Run("MismatchedFooterColumns", func(t *testing.T) {
+ var buf bytes.Buffer
+ table := newTableWriter(&buf)
+
+ headers := []string{"A", "B", "C"}
+ rows := [][]string{{"x", "y", "z"}}
+ footer := []string{"total", "sum"} // Missing column
+
+ table.SetHeader(headers)
+ table.AppendBulk(rows)
+ table.SetFooter(footer)
+ table.Render()
+
+ output := buf.String()
+ if !strings.Contains(output, "footer has 2 columns, expected 3") {
+ t.Errorf("Expected validation error for footer, got: %s", output)
+ }
+ })
+}
diff --git a/rlp/unsafe.go b/core/rawdb/database_tablewriter_unix.go
similarity index 71%
rename from rlp/unsafe.go
rename to core/rawdb/database_tablewriter_unix.go
index 10868caaf2..8bec5396e8 100644
--- a/rlp/unsafe.go
+++ b/core/rawdb/database_tablewriter_unix.go
@@ -1,4 +1,4 @@
-// Copyright 2021 The go-ethereum Authors
+// 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
@@ -14,17 +14,20 @@
// 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
+//go:build !tinygo
+// +build !tinygo
-package rlp
+package rawdb
import (
- "reflect"
- "unsafe"
+ "io"
+
+ "github.com/olekukonko/tablewriter"
)
-// 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)
+// Re-export the real tablewriter types and functions
+type Table = tablewriter.Table
+
+func newTableWriter(w io.Writer) *Table {
+ return tablewriter.NewWriter(w)
}
diff --git a/core/rawdb/schema.go b/core/rawdb/schema.go
index 72f9bd34ec..3588063468 100644
--- a/core/rawdb/schema.go
+++ b/core/rawdb/schema.go
@@ -384,21 +384,48 @@ func accountHistoryIndexKey(addressHash common.Hash) []byte {
// storageHistoryIndexKey = StateHistoryStorageMetadataPrefix + addressHash + storageHash
func storageHistoryIndexKey(addressHash common.Hash, storageHash common.Hash) []byte {
- return append(append(StateHistoryStorageMetadataPrefix, addressHash.Bytes()...), storageHash.Bytes()...)
+ totalLen := len(StateHistoryStorageMetadataPrefix) + 2*common.HashLength
+ out := make([]byte, totalLen)
+
+ off := 0
+ off += copy(out[off:], StateHistoryStorageMetadataPrefix)
+ off += copy(out[off:], addressHash.Bytes())
+ copy(out[off:], storageHash.Bytes())
+
+ return out
}
// accountHistoryIndexBlockKey = StateHistoryAccountBlockPrefix + addressHash + blockID
func accountHistoryIndexBlockKey(addressHash common.Hash, blockID uint32) []byte {
- var buf [4]byte
- binary.BigEndian.PutUint32(buf[:], blockID)
- return append(append(StateHistoryAccountBlockPrefix, addressHash.Bytes()...), buf[:]...)
+ var buf4 [4]byte
+ binary.BigEndian.PutUint32(buf4[:], blockID)
+
+ totalLen := len(StateHistoryAccountBlockPrefix) + common.HashLength + 4
+ out := make([]byte, totalLen)
+
+ off := 0
+ off += copy(out[off:], StateHistoryAccountBlockPrefix)
+ off += copy(out[off:], addressHash.Bytes())
+ copy(out[off:], buf4[:])
+
+ return out
}
// storageHistoryIndexBlockKey = StateHistoryStorageBlockPrefix + addressHash + storageHash + blockID
func storageHistoryIndexBlockKey(addressHash common.Hash, storageHash common.Hash, blockID uint32) []byte {
- var buf [4]byte
- binary.BigEndian.PutUint32(buf[:], blockID)
- return append(append(append(StateHistoryStorageBlockPrefix, addressHash.Bytes()...), storageHash.Bytes()...), buf[:]...)
+ var buf4 [4]byte
+ binary.BigEndian.PutUint32(buf4[:], blockID)
+
+ totalLen := len(StateHistoryStorageBlockPrefix) + 2*common.HashLength + 4
+ out := make([]byte, totalLen)
+
+ off := 0
+ off += copy(out[off:], StateHistoryStorageBlockPrefix)
+ off += copy(out[off:], addressHash.Bytes())
+ off += copy(out[off:], storageHash.Bytes())
+ copy(out[off:], buf4[:])
+
+ return out
}
// transitionStateKey = transitionStatusKey + hash
diff --git a/core/state/database.go b/core/state/database.go
index b46e5d500d..3a0ac422ee 100644
--- a/core/state/database.go
+++ b/core/state/database.go
@@ -81,11 +81,19 @@ type Trie interface {
// be returned.
GetAccount(address common.Address) (*types.StateAccount, error)
+ // PrefetchAccount attempts to resolve specific accounts from the database
+ // to accelerate subsequent trie operations.
+ PrefetchAccount([]common.Address) error
+
// GetStorage returns the value for key stored in the trie. The value bytes
// must not be modified by the caller. If a node was not found in the database,
// a trie.MissingNodeError is returned.
GetStorage(addr common.Address, key []byte) ([]byte, error)
+ // PrefetchStorage attempts to resolve specific storage slots from the database
+ // to accelerate subsequent trie operations.
+ PrefetchStorage(addr common.Address, keys [][]byte) error
+
// UpdateAccount abstracts an account write to the trie. It encodes the
// provided account object with associated algorithm and then updates it
// in the trie with provided address.
@@ -122,7 +130,7 @@ type Trie interface {
// Witness returns a set containing all trie nodes that have been accessed.
// The returned map could be nil if the witness is empty.
- Witness() map[string]struct{}
+ Witness() map[string][]byte
// NodeIterator returns an iterator that returns nodes of the trie. Iteration
// starts at the key after the given start key. And error will be returned
diff --git a/core/state/reader.go b/core/state/reader.go
index f56a1bfae1..4b854fefcc 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.NewTransitionTrie(mpt, tr.(*trie.VerkleTrie), false)
+ }
}
if err != nil {
return nil, err
diff --git a/core/state/statedb.go b/core/state/statedb.go
index 7aa6780cfa..6474d3a2fa 100644
--- a/core/state/statedb.go
+++ b/core/state/statedb.go
@@ -136,7 +136,8 @@ type StateDB struct {
journal *journal
// State witness if cross validation is needed
- witness *stateless.Witness
+ witness *stateless.Witness
+ witnessStats *stateless.WitnessStats
// Measurements gathered during execution for debugging purposes
AccountReads time.Duration
@@ -191,12 +192,13 @@ func NewWithReader(root common.Hash, db Database, reader Reader) (*StateDB, erro
// StartPrefetcher initializes a new trie prefetcher to pull in nodes from the
// state trie concurrently while the state is mutated so that when we reach the
// commit phase, most of the needed data is already hot.
-func (s *StateDB) StartPrefetcher(namespace string, witness *stateless.Witness) {
+func (s *StateDB) StartPrefetcher(namespace string, witness *stateless.Witness, witnessStats *stateless.WitnessStats) {
// Terminate any previously running prefetcher
s.StopPrefetcher()
// Enable witness collection if requested
s.witness = witness
+ s.witnessStats = witnessStats
// With the switch to the Proof-of-Stake consensus algorithm, block production
// rewards are now handled at the consensus layer. Consequently, a block may
@@ -858,9 +860,17 @@ func (s *StateDB) IntermediateRoot(deleteEmptyObjects bool) common.Hash {
continue
}
if trie := obj.getPrefetchedTrie(); trie != nil {
- s.witness.AddState(trie.Witness())
+ witness := trie.Witness()
+ s.witness.AddState(witness)
+ if s.witnessStats != nil {
+ s.witnessStats.Add(witness, obj.addrHash)
+ }
} else if obj.trie != nil {
- s.witness.AddState(obj.trie.Witness())
+ witness := obj.trie.Witness()
+ s.witness.AddState(witness)
+ if s.witnessStats != nil {
+ s.witnessStats.Add(witness, obj.addrHash)
+ }
}
}
// Pull in only-read and non-destructed trie witnesses
@@ -874,9 +884,17 @@ func (s *StateDB) IntermediateRoot(deleteEmptyObjects bool) common.Hash {
continue
}
if trie := obj.getPrefetchedTrie(); trie != nil {
- s.witness.AddState(trie.Witness())
+ witness := trie.Witness()
+ s.witness.AddState(witness)
+ if s.witnessStats != nil {
+ s.witnessStats.Add(witness, obj.addrHash)
+ }
} else if obj.trie != nil {
- s.witness.AddState(obj.trie.Witness())
+ witness := obj.trie.Witness()
+ s.witness.AddState(witness)
+ if s.witnessStats != nil {
+ s.witnessStats.Add(witness, obj.addrHash)
+ }
}
}
}
@@ -942,7 +960,11 @@ func (s *StateDB) IntermediateRoot(deleteEmptyObjects bool) common.Hash {
// If witness building is enabled, gather the account trie witness
if s.witness != nil {
- s.witness.AddState(s.trie.Witness())
+ witness := s.trie.Witness()
+ s.witness.AddState(witness)
+ if s.witnessStats != nil {
+ s.witnessStats.Add(witness, common.Hash{})
+ }
}
return hash
}
@@ -977,7 +999,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 +1050,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 +1182,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/core/state/trie_prefetcher.go b/core/state/trie_prefetcher.go
index 6f492cf9f2..a9faddcdff 100644
--- a/core/state/trie_prefetcher.go
+++ b/core/state/trie_prefetcher.go
@@ -388,6 +388,10 @@ func (sf *subfetcher) loop() {
sf.tasks = nil
sf.lock.Unlock()
+ var (
+ addresses []common.Address
+ slots [][]byte
+ )
for _, task := range tasks {
if task.addr != nil {
key := *task.addr
@@ -400,6 +404,7 @@ func (sf *subfetcher) loop() {
sf.dupsCross++
continue
}
+ sf.seenReadAddr[key] = struct{}{}
} else {
if _, ok := sf.seenReadAddr[key]; ok {
sf.dupsCross++
@@ -409,7 +414,9 @@ func (sf *subfetcher) loop() {
sf.dupsWrite++
continue
}
+ sf.seenWriteAddr[key] = struct{}{}
}
+ addresses = append(addresses, *task.addr)
} else {
key := *task.slot
if task.read {
@@ -421,6 +428,7 @@ func (sf *subfetcher) loop() {
sf.dupsCross++
continue
}
+ sf.seenReadSlot[key] = struct{}{}
} else {
if _, ok := sf.seenReadSlot[key]; ok {
sf.dupsCross++
@@ -430,25 +438,19 @@ func (sf *subfetcher) loop() {
sf.dupsWrite++
continue
}
+ sf.seenWriteSlot[key] = struct{}{}
}
+ slots = append(slots, key.Bytes())
}
- if task.addr != nil {
- sf.trie.GetAccount(*task.addr)
- } else {
- sf.trie.GetStorage(sf.addr, (*task.slot)[:])
+ }
+ if len(addresses) != 0 {
+ if err := sf.trie.PrefetchAccount(addresses); err != nil {
+ log.Error("Failed to prefetch accounts", "err", err)
}
- if task.read {
- if task.addr != nil {
- sf.seenReadAddr[*task.addr] = struct{}{}
- } else {
- sf.seenReadSlot[*task.slot] = struct{}{}
- }
- } else {
- if task.addr != nil {
- sf.seenWriteAddr[*task.addr] = struct{}{}
- } else {
- sf.seenWriteSlot[*task.slot] = struct{}{}
- }
+ }
+ if len(slots) != 0 {
+ if err := sf.trie.PrefetchStorage(sf.addr, slots); err != nil {
+ log.Error("Failed to prefetch storage", "err", err)
}
}
diff --git a/core/state_prefetcher.go b/core/state_prefetcher.go
index c0ce705c77..1c738c1e38 100644
--- a/core/state_prefetcher.go
+++ b/core/state_prefetcher.go
@@ -111,12 +111,6 @@ func (p *statePrefetcher) Prefetch(block *types.Block, statedb *state.StateDB, c
fails.Add(1)
return nil // Ugh, something went horribly wrong, bail out
}
- // Pre-load trie nodes for the intermediate root.
- //
- // This operation incurs significant memory allocations due to
- // trie hashing and node decoding. TODO(rjl493456442): investigate
- // ways to mitigate this overhead.
- stateCpy.IntermediateRoot(true)
return nil
})
}
diff --git a/core/stateless/stats.go b/core/stateless/stats.go
new file mode 100644
index 0000000000..46022ac74b
--- /dev/null
+++ b/core/stateless/stats.go
@@ -0,0 +1,108 @@
+// 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 stateless
+
+import (
+ "maps"
+
+ "github.com/ethereum/go-ethereum/common"
+ "github.com/ethereum/go-ethereum/metrics"
+)
+
+var (
+ accountTrieDepthAvg = metrics.NewRegisteredGauge("witness/trie/account/depth/avg", nil)
+ accountTrieDepthMin = metrics.NewRegisteredGauge("witness/trie/account/depth/min", nil)
+ accountTrieDepthMax = metrics.NewRegisteredGauge("witness/trie/account/depth/max", nil)
+
+ storageTrieDepthAvg = metrics.NewRegisteredGauge("witness/trie/storage/depth/avg", nil)
+ storageTrieDepthMin = metrics.NewRegisteredGauge("witness/trie/storage/depth/min", nil)
+ storageTrieDepthMax = metrics.NewRegisteredGauge("witness/trie/storage/depth/max", nil)
+)
+
+// depthStats tracks min/avg/max statistics for trie access depths.
+type depthStats struct {
+ totalDepth int64
+ samples int64
+ minDepth int64
+ maxDepth int64
+}
+
+// newDepthStats creates a new depthStats with default values.
+func newDepthStats() *depthStats {
+ return &depthStats{minDepth: -1}
+}
+
+// add records a new depth sample.
+func (d *depthStats) add(n int64) {
+ if n < 0 {
+ return
+ }
+ d.totalDepth += n
+ d.samples++
+
+ if d.minDepth == -1 || n < d.minDepth {
+ d.minDepth = n
+ }
+ if n > d.maxDepth {
+ d.maxDepth = n
+ }
+}
+
+// report uploads the collected statistics into the provided gauges.
+func (d *depthStats) report(maxGauge, minGauge, avgGauge *metrics.Gauge) {
+ if d.samples == 0 {
+ return
+ }
+ maxGauge.Update(d.maxDepth)
+ minGauge.Update(d.minDepth)
+ avgGauge.Update(d.totalDepth / d.samples)
+}
+
+// WitnessStats aggregates statistics for account and storage trie accesses.
+type WitnessStats struct {
+ accountTrie *depthStats
+ storageTrie *depthStats
+}
+
+// NewWitnessStats creates a new WitnessStats collector.
+func NewWitnessStats() *WitnessStats {
+ return &WitnessStats{
+ accountTrie: newDepthStats(),
+ storageTrie: newDepthStats(),
+ }
+}
+
+// Add records trie access depths from the given node paths.
+// If `owner` is the zero hash, accesses are attributed to the account trie;
+// otherwise, they are attributed to the storage trie of that account.
+func (s *WitnessStats) Add(nodes map[string][]byte, owner common.Hash) {
+ if owner == (common.Hash{}) {
+ for path := range maps.Keys(nodes) {
+ s.accountTrie.add(int64(len(path)))
+ }
+ } else {
+ for path := range maps.Keys(nodes) {
+ s.storageTrie.add(int64(len(path)))
+ }
+ }
+}
+
+// ReportMetrics reports the collected statistics to the global metrics registry.
+func (s *WitnessStats) ReportMetrics() {
+ s.accountTrie.report(accountTrieDepthMax, accountTrieDepthMin, accountTrieDepthAvg)
+ s.storageTrie.report(storageTrieDepthMax, storageTrieDepthMin, storageTrieDepthAvg)
+}
diff --git a/core/stateless/witness.go b/core/stateless/witness.go
index aecfad1d52..371a128f48 100644
--- a/core/stateless/witness.go
+++ b/core/stateless/witness.go
@@ -58,7 +58,7 @@ func NewWitness(context *types.Header, chain HeaderReader) (*Witness, error) {
}
headers = append(headers, parent)
}
- // Create the wtness with a reconstructed gutted out block
+ // Create the witness with a reconstructed gutted out block
return &Witness{
context: context,
Headers: headers,
@@ -88,14 +88,16 @@ func (w *Witness) AddCode(code []byte) {
}
// AddState inserts a batch of MPT trie nodes into the witness.
-func (w *Witness) AddState(nodes map[string]struct{}) {
+func (w *Witness) AddState(nodes map[string][]byte) {
if len(nodes) == 0 {
return
}
w.lock.Lock()
defer w.lock.Unlock()
- maps.Copy(w.State, nodes)
+ for _, value := range nodes {
+ w.State[string(value)] = struct{}{}
+ }
}
// Copy deep-copies the witness object. Witness.Block isn't deep-copied as it
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/txpool/legacypool/legacypool.go b/core/txpool/legacypool/legacypool.go
index 93a003c172..425def170b 100644
--- a/core/txpool/legacypool/legacypool.go
+++ b/core/txpool/legacypool/legacypool.go
@@ -514,26 +514,15 @@ func (pool *LegacyPool) Pending(filter txpool.PendingFilter) map[common.Address]
pool.mu.Lock()
defer pool.mu.Unlock()
- // Convert the new uint256.Int types to the old big.Int ones used by the legacy pool
- var (
- minTipBig *big.Int
- baseFeeBig *big.Int
- )
- if filter.MinTip != nil {
- minTipBig = filter.MinTip.ToBig()
- }
- if filter.BaseFee != nil {
- baseFeeBig = filter.BaseFee.ToBig()
- }
pending := make(map[common.Address][]*txpool.LazyTransaction, len(pool.pending))
for addr, list := range pool.pending {
txs := list.Flatten()
// If the miner requests tip enforcement, cap the lists now
- if minTipBig != nil || filter.GasLimitCap != 0 {
+ if filter.MinTip != nil || filter.GasLimitCap != 0 {
for i, tx := range txs {
- if minTipBig != nil {
- if tx.EffectiveGasTipIntCmp(minTipBig, baseFeeBig) < 0 {
+ if filter.MinTip != nil {
+ if tx.EffectiveGasTipIntCmp(filter.MinTip, filter.BaseFee) < 0 {
txs = txs[:i]
break
}
diff --git a/core/txpool/legacypool/list.go b/core/txpool/legacypool/list.go
index 736c28ec4a..507c0b429a 100644
--- a/core/txpool/legacypool/list.go
+++ b/core/txpool/legacypool/list.go
@@ -475,7 +475,7 @@ func (l *list) subTotalCost(txs []*types.Transaction) {
// then the heap is sorted based on the effective tip based on the given base fee.
// If baseFee is nil then the sorting is based on gasFeeCap.
type priceHeap struct {
- baseFee *big.Int // heap should always be re-sorted after baseFee is changed
+ baseFee *uint256.Int // heap should always be re-sorted after baseFee is changed
list []*types.Transaction
}
@@ -677,6 +677,10 @@ func (l *pricedList) Reheap() {
// SetBaseFee updates the base fee and triggers a re-heap. Note that Removed is not
// necessary to call right before SetBaseFee when processing a new block.
func (l *pricedList) SetBaseFee(baseFee *big.Int) {
- l.urgent.baseFee = baseFee
+ base := new(uint256.Int)
+ if baseFee != nil {
+ base.SetFromBig(baseFee)
+ }
+ l.urgent.baseFee = base
l.Reheap()
}
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/transaction.go b/core/types/transaction.go
index 733b6510f1..be8e90364e 100644
--- a/core/types/transaction.go
+++ b/core/types/transaction.go
@@ -28,6 +28,7 @@ import (
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/rlp"
+ "github.com/holiman/uint256"
)
var (
@@ -36,6 +37,7 @@ var (
ErrInvalidTxType = errors.New("transaction type not valid in this context")
ErrTxTypeNotSupported = errors.New("transaction type not supported")
ErrGasFeeCapTooLow = errors.New("fee cap less than base fee")
+ ErrUint256Overflow = errors.New("bigint overflow, too large for uint256")
errShortTypedTx = errors.New("typed transaction too short")
errInvalidYParity = errors.New("'yParity' field must be 0 or 1")
errVYParityMismatch = errors.New("'v' and 'yParity' fields do not match")
@@ -352,54 +354,66 @@ func (tx *Transaction) GasTipCapIntCmp(other *big.Int) int {
}
// EffectiveGasTip returns the effective miner gasTipCap for the given base fee.
-// Note: if the effective gasTipCap is negative, this method returns both error
-// the actual negative value, _and_ ErrGasFeeCapTooLow
+// Note: if the effective gasTipCap would be negative, this method
+// returns ErrGasFeeCapTooLow, and value is undefined.
func (tx *Transaction) EffectiveGasTip(baseFee *big.Int) (*big.Int, error) {
- dst := new(big.Int)
- err := tx.calcEffectiveGasTip(dst, baseFee)
- return dst, err
+ dst := new(uint256.Int)
+ base := new(uint256.Int)
+ if baseFee != nil {
+ if base.SetFromBig(baseFee) {
+ return nil, ErrUint256Overflow
+ }
+ }
+ err := tx.calcEffectiveGasTip(dst, base)
+ return dst.ToBig(), err
}
// calcEffectiveGasTip calculates the effective gas tip of the transaction and
// saves the result to dst.
-func (tx *Transaction) calcEffectiveGasTip(dst *big.Int, baseFee *big.Int) error {
+func (tx *Transaction) calcEffectiveGasTip(dst *uint256.Int, baseFee *uint256.Int) error {
if baseFee == nil {
- dst.Set(tx.inner.gasTipCap())
+ if dst.SetFromBig(tx.inner.gasTipCap()) {
+ return ErrUint256Overflow
+ }
return nil
}
var err error
- gasFeeCap := tx.inner.gasFeeCap()
- if gasFeeCap.Cmp(baseFee) < 0 {
+ if dst.SetFromBig(tx.inner.gasFeeCap()) {
+ return ErrUint256Overflow
+ }
+ if dst.Cmp(baseFee) < 0 {
err = ErrGasFeeCapTooLow
}
- dst.Sub(gasFeeCap, baseFee)
- gasTipCap := tx.inner.gasTipCap()
+ dst.Sub(dst, baseFee)
+ gasTipCap := new(uint256.Int)
+ if gasTipCap.SetFromBig(tx.inner.gasTipCap()) {
+ return ErrUint256Overflow
+ }
if gasTipCap.Cmp(dst) < 0 {
dst.Set(gasTipCap)
}
return err
}
-// EffectiveGasTipCmp compares the effective gasTipCap of two transactions assuming the given base fee.
-func (tx *Transaction) EffectiveGasTipCmp(other *Transaction, baseFee *big.Int) int {
+func (tx *Transaction) EffectiveGasTipCmp(other *Transaction, baseFee *uint256.Int) int {
if baseFee == nil {
return tx.GasTipCapCmp(other)
}
// Use more efficient internal method.
- txTip, otherTip := new(big.Int), new(big.Int)
+ txTip, otherTip := new(uint256.Int), new(uint256.Int)
tx.calcEffectiveGasTip(txTip, baseFee)
other.calcEffectiveGasTip(otherTip, baseFee)
return txTip.Cmp(otherTip)
}
// EffectiveGasTipIntCmp compares the effective gasTipCap of a transaction to the given gasTipCap.
-func (tx *Transaction) EffectiveGasTipIntCmp(other *big.Int, baseFee *big.Int) int {
+func (tx *Transaction) EffectiveGasTipIntCmp(other *uint256.Int, baseFee *uint256.Int) int {
if baseFee == nil {
- return tx.GasTipCapIntCmp(other)
+ return tx.GasTipCapIntCmp(other.ToBig())
}
- txTip := new(big.Int)
+ txTip := new(uint256.Int)
tx.calcEffectiveGasTip(txTip, baseFee)
return txTip.Cmp(other)
}
diff --git a/core/types/transaction_test.go b/core/types/transaction_test.go
index 7d5e2f058a..cc41674dfd 100644
--- a/core/types/transaction_test.go
+++ b/core/types/transaction_test.go
@@ -31,6 +31,7 @@ import (
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/params"
"github.com/ethereum/go-ethereum/rlp"
+ "github.com/holiman/uint256"
)
// The values in those tests are from the Transaction Tests
@@ -609,12 +610,12 @@ func BenchmarkEffectiveGasTip(b *testing.B) {
Data: nil,
}
tx, _ := SignNewTx(key, signer, txdata)
- baseFee := big.NewInt(1000000000) // 1 gwei
+ baseFee := uint256.NewInt(1000000000) // 1 gwei
b.Run("Original", func(b *testing.B) {
b.ReportAllocs()
for i := 0; i < b.N; i++ {
- _, err := tx.EffectiveGasTip(baseFee)
+ _, err := tx.EffectiveGasTip(baseFee.ToBig())
if err != nil {
b.Fatal(err)
}
@@ -623,7 +624,7 @@ func BenchmarkEffectiveGasTip(b *testing.B) {
b.Run("IntoMethod", func(b *testing.B) {
b.ReportAllocs()
- dst := new(big.Int)
+ dst := new(uint256.Int)
for i := 0; i < b.N; i++ {
err := tx.calcEffectiveGasTip(dst, baseFee)
if err != nil {
@@ -634,9 +635,6 @@ func BenchmarkEffectiveGasTip(b *testing.B) {
}
func TestEffectiveGasTipInto(t *testing.T) {
- signer := LatestSigner(params.TestChainConfig)
- key, _ := crypto.GenerateKey()
-
testCases := []struct {
tipCap int64
feeCap int64
@@ -652,8 +650,26 @@ func TestEffectiveGasTipInto(t *testing.T) {
{tipCap: 50, feeCap: 100, baseFee: nil}, // nil base fee
}
+ // original, non-allocation golfed version
+ orig := func(tx *Transaction, baseFee *big.Int) (*big.Int, error) {
+ if baseFee == nil {
+ return tx.GasTipCap(), nil
+ }
+ var err error
+ gasFeeCap := tx.GasFeeCap()
+ if gasFeeCap.Cmp(baseFee) < 0 {
+ err = ErrGasFeeCapTooLow
+ }
+ gasFeeCap = gasFeeCap.Sub(gasFeeCap, baseFee)
+ gasTipCap := tx.GasTipCap()
+ if gasTipCap.Cmp(gasFeeCap) < 0 {
+ return gasTipCap, err
+ }
+ return gasFeeCap, err
+ }
+
for i, tc := range testCases {
- txdata := &DynamicFeeTx{
+ tx := NewTx(&DynamicFeeTx{
ChainID: big.NewInt(1),
Nonce: 0,
GasTipCap: big.NewInt(tc.tipCap),
@@ -662,27 +678,28 @@ func TestEffectiveGasTipInto(t *testing.T) {
To: &common.Address{},
Value: big.NewInt(0),
Data: nil,
- }
- tx, _ := SignNewTx(key, signer, txdata)
+ })
var baseFee *big.Int
+ var baseFee2 *uint256.Int
if tc.baseFee != nil {
baseFee = big.NewInt(*tc.baseFee)
+ baseFee2 = uint256.NewInt(uint64(*tc.baseFee))
}
// Get result from original method
- orig, origErr := tx.EffectiveGasTip(baseFee)
+ orig, origErr := orig(tx, baseFee)
// Get result from new method
- dst := new(big.Int)
- newErr := tx.calcEffectiveGasTip(dst, baseFee)
+ dst := new(uint256.Int)
+ newErr := tx.calcEffectiveGasTip(dst, baseFee2)
// Compare results
if (origErr != nil) != (newErr != nil) {
t.Fatalf("case %d: error mismatch: orig %v, new %v", i, origErr, newErr)
}
- if orig.Cmp(dst) != 0 {
+ if origErr == nil && orig.Cmp(dst.ToBig()) != 0 {
t.Fatalf("case %d: result mismatch: orig %v, new %v", i, orig, dst)
}
}
@@ -692,3 +709,28 @@ func TestEffectiveGasTipInto(t *testing.T) {
func intPtr(i int64) *int64 {
return &i
}
+
+func BenchmarkEffectiveGasTipCmp(b *testing.B) {
+ signer := LatestSigner(params.TestChainConfig)
+ key, _ := crypto.GenerateKey()
+ txdata := &DynamicFeeTx{
+ ChainID: big.NewInt(1),
+ Nonce: 0,
+ GasTipCap: big.NewInt(2000000000),
+ GasFeeCap: big.NewInt(3000000000),
+ Gas: 21000,
+ To: &common.Address{},
+ Value: big.NewInt(0),
+ Data: nil,
+ }
+ tx, _ := SignNewTx(key, signer, txdata)
+ other, _ := SignNewTx(key, signer, txdata)
+ baseFee := uint256.NewInt(1000000000) // 1 gwei
+
+ b.Run("Original", func(b *testing.B) {
+ b.ReportAllocs()
+ for i := 0; i < b.N; i++ {
+ tx.EffectiveGasTipCmp(other, baseFee)
+ }
+ })
+}
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)
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..e9b80280bf 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
@@ -500,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))
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..44d3e81a9c 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))
@@ -1004,9 +1003,9 @@ 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) {
- scope.Stack.dup(int(size))
+func makeDup(size int) executionFunc {
+ return func(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) {
+ scope.Stack.dup(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..52dbe83d86 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"
)
@@ -35,6 +33,7 @@ type Config struct {
ExtraEips []int // Additional EIPS that are to be enabled
StatelessSelfValidation bool // Generate execution witnesses and self-check against them (testing purpose)
+ EnableWitnessStats bool // Whether trie access statistics collection is enabled
}
// ScopeContext contains the things that are per-call, such as stack and memory,
@@ -89,93 +88,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 +117,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 +131,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 +152,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 +171,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 +221,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 +236,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 +249,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/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()
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
)
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]))
diff --git a/eth/catalyst/api.go b/eth/catalyst/api.go
index 038328d9ba..7f6dd40907 100644
--- a/eth/catalyst/api.go
+++ b/eth/catalyst/api.go
@@ -20,10 +20,12 @@ package catalyst
import (
"errors"
"fmt"
+ "reflect"
"strconv"
"sync"
"sync/atomic"
"time"
+ "unicode"
"github.com/ethereum/go-ethereum/beacon/engine"
"github.com/ethereum/go-ethereum/common"
@@ -80,41 +82,6 @@ const (
beaconUpdateWarnFrequency = 5 * time.Minute
)
-// All methods provided over the engine endpoint.
-var caps = []string{
- "engine_forkchoiceUpdatedV1",
- "engine_forkchoiceUpdatedV2",
- "engine_forkchoiceUpdatedV3",
- "engine_forkchoiceUpdatedWithWitnessV1",
- "engine_forkchoiceUpdatedWithWitnessV2",
- "engine_forkchoiceUpdatedWithWitnessV3",
- "engine_exchangeTransitionConfigurationV1",
- "engine_getPayloadV1",
- "engine_getPayloadV2",
- "engine_getPayloadV3",
- "engine_getPayloadV4",
- "engine_getPayloadV5",
- "engine_getBlobsV1",
- "engine_getBlobsV2",
- "engine_newPayloadV1",
- "engine_newPayloadV2",
- "engine_newPayloadV3",
- "engine_newPayloadV4",
- "engine_newPayloadWithWitnessV1",
- "engine_newPayloadWithWitnessV2",
- "engine_newPayloadWithWitnessV3",
- "engine_newPayloadWithWitnessV4",
- "engine_executeStatelessPayloadV1",
- "engine_executeStatelessPayloadV2",
- "engine_executeStatelessPayloadV3",
- "engine_executeStatelessPayloadV4",
- "engine_getPayloadBodiesByHashV1",
- "engine_getPayloadBodiesByHashV2",
- "engine_getPayloadBodiesByRangeV1",
- "engine_getPayloadBodiesByRangeV2",
- "engine_getClientVersionV1",
-}
-
var (
// Number of blobs requested via getBlobsV2
getBlobsRequestedCounter = metrics.NewRegisteredCounter("engine/getblobs/requested", nil)
@@ -916,6 +883,15 @@ func (api *ConsensusAPI) checkFork(timestamp uint64, forks ...forks.Fork) bool {
// ExchangeCapabilities returns the current methods provided by this node.
func (api *ConsensusAPI) ExchangeCapabilities([]string) []string {
+ valueT := reflect.TypeOf(api)
+ caps := make([]string, 0, valueT.NumMethod())
+ for i := 0; i < valueT.NumMethod(); i++ {
+ name := []rune(valueT.Method(i).Name)
+ if string(name) == "ExchangeCapabilities" {
+ continue
+ }
+ caps = append(caps, "engine_"+string(unicode.ToLower(name[0]))+string(name[1:]))
+ }
return caps
}
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}
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
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)
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)
}
diff --git a/eth/syncer/syncer.go b/eth/syncer/syncer.go
index 5c4d2401e9..6b33ec54ba 100644
--- a/eth/syncer/syncer.go
+++ b/eth/syncer/syncer.go
@@ -89,6 +89,7 @@ func (s *Syncer) run() {
target *types.Header
ticker = time.NewTicker(time.Second * 5)
)
+ defer ticker.Stop()
for {
select {
case req := <-s.request:
@@ -99,7 +100,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 {
diff --git a/eth/tracers/api_test.go b/eth/tracers/api_test.go
index 7ed2a5936e..39c39ff05d 100644
--- a/eth/tracers/api_test.go
+++ b/eth/tracers/api_test.go
@@ -527,7 +527,7 @@ func TestTraceTransaction(t *testing.T) {
b.AddTx(tx)
target = tx.Hash()
})
- defer backend.chain.Stop()
+ defer backend.teardown()
api := NewAPI(backend)
result, err := api.TraceTransaction(context.Background(), target, nil)
if err != nil {
@@ -584,7 +584,7 @@ func TestTraceBlock(t *testing.T) {
b.AddTx(tx)
txHash = tx.Hash()
})
- defer backend.chain.Stop()
+ defer backend.teardown()
api := NewAPI(backend)
var testSuite = []struct {
@@ -681,7 +681,7 @@ func TestTracingWithOverrides(t *testing.T) {
signer, accounts[0].key)
b.AddTx(tx)
})
- defer backend.chain.Stop()
+ defer backend.teardown()
api := NewAPI(backend)
randomAccounts := newAccounts(3)
type res struct {
@@ -1105,6 +1105,7 @@ func TestTraceChain(t *testing.T) {
nonce += 1
}
})
+ defer backend.teardown()
backend.refHook = func() { ref.Add(1) }
backend.relHook = func() { rel.Add(1) }
api := NewAPI(backend)
@@ -1212,7 +1213,7 @@ func TestTraceBlockWithBasefee(t *testing.T) {
txHash = tx.Hash()
baseFee.Set(b.BaseFee())
})
- defer backend.chain.Stop()
+ defer backend.teardown()
api := NewAPI(backend)
var testSuite = []struct {
@@ -1298,7 +1299,7 @@ func TestStandardTraceBlockToFile(t *testing.T) {
b.AddTx(tx)
txHashs = append(txHashs, tx.Hash())
})
- defer backend.chain.Stop()
+ defer backend.teardown()
var testSuite = []struct {
blockNumber rpc.BlockNumber
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/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)
}
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
}
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 {
diff --git a/ethclient/gethclient/gethclient.go b/ethclient/gethclient/gethclient.go
index d030878e54..54997cbf51 100644
--- a/ethclient/gethclient/gethclient.go
+++ b/ethclient/gethclient/gethclient.go
@@ -209,7 +209,7 @@ func (ec *Client) SubscribePendingTransactions(ctx context.Context, ch chan<- co
// and returns them as a JSON object.
func (ec *Client) TraceTransaction(ctx context.Context, hash common.Hash, config *tracers.TraceConfig) (any, error) {
var result any
- err := ec.c.CallContext(ctx, &result, "debug_traceTransaction", hash.Hex(), config)
+ err := ec.c.CallContext(ctx, &result, "debug_traceTransaction", hash, config)
if err != nil {
return nil, err
}
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()
}
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=
diff --git a/graphql/graphql_test.go b/graphql/graphql_test.go
index 0f6ba10b90..ca864d5fb2 100644
--- a/graphql/graphql_test.go
+++ b/graphql/graphql_test.go
@@ -430,6 +430,40 @@ func TestWithdrawals(t *testing.T) {
}
}
+// TestGraphQLMaxDepth ensures that queries exceeding the configured maximum depth
+// are rejected to prevent resource exhaustion from deeply nested operations.
+func TestGraphQLMaxDepth(t *testing.T) {
+ stack := createNode(t)
+ defer stack.Close()
+
+ h, err := newHandler(stack, nil, nil, []string{}, []string{})
+ if err != nil {
+ t.Fatalf("could not create graphql service: %v", err)
+ }
+
+ var b strings.Builder
+ for i := 0; i < maxQueryDepth+1; i++ {
+ b.WriteString("ommers{")
+ }
+ b.WriteString("number")
+ for i := 0; i < maxQueryDepth+1; i++ {
+ b.WriteString("}")
+ }
+ query := fmt.Sprintf("{block{%s}}", b.String())
+
+ res := h.Schema.Exec(context.Background(), query, "", nil)
+ var found bool
+ for _, err := range res.Errors {
+ if err.Rule == "MaxDepthExceeded" {
+ found = true
+ break
+ }
+ }
+ if !found {
+ t.Fatalf("expected max depth exceeded error, got %v", res.Errors)
+ }
+}
+
func createNode(t *testing.T) *node.Node {
stack, err := node.New(&node.Config{
HTTPHost: "127.0.0.1",
diff --git a/graphql/service.go b/graphql/service.go
index 584165bdb8..9381a51da6 100644
--- a/graphql/service.go
+++ b/graphql/service.go
@@ -32,6 +32,9 @@ import (
gqlErrors "github.com/graph-gophers/graphql-go/errors"
)
+// maxQueryDepth limits the maximum field nesting depth allowed in GraphQL queries.
+const maxQueryDepth = 20
+
type handler struct {
Schema *graphql.Schema
}
@@ -116,7 +119,7 @@ func New(stack *node.Node, backend ethapi.Backend, filterSystem *filters.FilterS
func newHandler(stack *node.Node, backend ethapi.Backend, filterSystem *filters.FilterSystem, cors, vhosts []string) (*handler, error) {
q := Resolver{backend, filterSystem}
- s, err := graphql.ParseSchema(schema, &q)
+ s, err := graphql.ParseSchema(schema, &q, graphql.MaxDepth(maxQueryDepth))
if err != nil {
return nil, err
}
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) {
diff --git a/internal/ethapi/api.go b/internal/ethapi/api.go
index 51b6ca3c44..16a56ccf07 100644
--- a/internal/ethapi/api.go
+++ b/internal/ethapi/api.go
@@ -597,19 +597,30 @@ func (api *BlockChainAPI) GetStorageAt(ctx context.Context, address common.Addre
// GetBlockReceipts returns the block receipts for the given block hash or number or tag.
func (api *BlockChainAPI) GetBlockReceipts(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash) ([]map[string]interface{}, error) {
- block, err := api.b.BlockByNumberOrHash(ctx, blockNrOrHash)
- if block == nil || err != nil {
- return nil, err
- }
- receipts, err := api.b.GetReceipts(ctx, block.Hash())
- if err != nil {
- return nil, err
+ var (
+ err error
+ block *types.Block
+ receipts types.Receipts
+ )
+ if blockNr, ok := blockNrOrHash.Number(); ok && blockNr == rpc.PendingBlockNumber {
+ block, receipts, _ = api.b.Pending()
+ if block == nil {
+ return nil, errors.New("pending receipts is not available")
+ }
+ } else {
+ block, err = api.b.BlockByNumberOrHash(ctx, blockNrOrHash)
+ if block == nil || err != nil {
+ return nil, err
+ }
+ receipts, err = api.b.GetReceipts(ctx, block.Hash())
+ if err != nil {
+ return nil, err
+ }
}
txs := block.Transactions()
if len(txs) != len(receipts) {
return nil, fmt.Errorf("receipts length mismatch: %d vs %d", len(txs), len(receipts))
}
-
// Derive the sender.
signer := types.MakeSigner(api.b.ChainConfig(), block.Number(), block.Time())
@@ -617,7 +628,6 @@ func (api *BlockChainAPI) GetBlockReceipts(ctx context.Context, blockNrOrHash rp
for i, receipt := range receipts {
result[i] = marshalReceipt(receipt, block.Hash(), block.NumberU64(), signer, txs[i], i)
}
-
return result, nil
}
diff --git a/internal/ethapi/api_test.go b/internal/ethapi/api_test.go
index de6d1d5e06..8e7220b5e4 100644
--- a/internal/ethapi/api_test.go
+++ b/internal/ethapi/api_test.go
@@ -434,11 +434,13 @@ func newTestAccountManager(t *testing.T) (*accounts.Manager, accounts.Account) {
}
type testBackend struct {
- db ethdb.Database
- chain *core.BlockChain
- pending *types.Block
- accman *accounts.Manager
- acc accounts.Account
+ db ethdb.Database
+ chain *core.BlockChain
+ accman *accounts.Manager
+ acc accounts.Account
+
+ pending *types.Block
+ pendingReceipts types.Receipts
}
func newTestBackend(t *testing.T, n int, gspec *core.Genesis, engine consensus.Engine, generator func(i int, b *core.BlockGen)) *testBackend {
@@ -449,24 +451,26 @@ func newTestBackend(t *testing.T, n int, gspec *core.Genesis, engine consensus.E
gspec.Alloc[acc.Address] = types.Account{Balance: big.NewInt(params.Ether)}
// Generate blocks for testing
- db, blocks, _ := core.GenerateChainWithGenesis(gspec, engine, n, generator)
+ db, blocks, receipts := core.GenerateChainWithGenesis(gspec, engine, n+1, generator)
chain, err := core.NewBlockChain(db, gspec, engine, options)
if err != nil {
t.Fatalf("failed to create tester chain: %v", err)
}
- if n, err := chain.InsertChain(blocks); err != nil {
+ if n, err := chain.InsertChain(blocks[:n]); err != nil {
t.Fatalf("block %d: failed to insert into chain: %v", n, err)
}
-
- backend := &testBackend{db: db, chain: chain, accman: accman, acc: acc}
+ backend := &testBackend{
+ db: db,
+ chain: chain,
+ accman: accman,
+ acc: acc,
+ pending: blocks[n],
+ pendingReceipts: receipts[n],
+ }
return backend
}
-func (b *testBackend) setPendingBlock(block *types.Block) {
- b.pending = block
-}
-
func (b testBackend) SyncProgress(ctx context.Context) ethereum.SyncProgress {
return ethereum.SyncProgress{}
}
@@ -558,7 +562,13 @@ func (b testBackend) StateAndHeaderByNumberOrHash(ctx context.Context, blockNrOr
}
panic("only implemented for number")
}
-func (b testBackend) Pending() (*types.Block, types.Receipts, *state.StateDB) { panic("implement me") }
+func (b testBackend) Pending() (*types.Block, types.Receipts, *state.StateDB) {
+ block := b.pending
+ if block == nil {
+ return nil, nil, nil
+ }
+ return block, b.pendingReceipts, nil
+}
func (b testBackend) GetReceipts(ctx context.Context, hash common.Hash) (types.Receipts, error) {
header, err := b.HeaderByHash(ctx, hash)
if header == nil || err != nil {
@@ -3141,21 +3151,6 @@ func TestRPCGetBlockOrHeader(t *testing.T) {
}
genBlocks = 10
signer = types.HomesteadSigner{}
- tx = types.NewTx(&types.LegacyTx{
- Nonce: 11,
- GasPrice: big.NewInt(11111),
- Gas: 1111,
- To: &acc2Addr,
- Value: big.NewInt(111),
- Data: []byte{0x11, 0x11, 0x11},
- })
- withdrawal = &types.Withdrawal{
- Index: 0,
- Validator: 1,
- Address: common.Address{0x12, 0x34},
- Amount: 10,
- }
- pending = types.NewBlock(&types.Header{Number: big.NewInt(11), Time: 42}, &types.Body{Transactions: types.Transactions{tx}, Withdrawals: types.Withdrawals{withdrawal}}, nil, blocktest.NewHasher())
)
backend := newTestBackend(t, genBlocks, genesis, ethash.NewFaker(), func(i int, b *core.BlockGen) {
// Transfer from account[0] to account[1]
@@ -3164,7 +3159,6 @@ func TestRPCGetBlockOrHeader(t *testing.T) {
tx, _ := types.SignTx(types.NewTx(&types.LegacyTx{Nonce: uint64(i), To: &acc2Addr, Value: big.NewInt(1000), Gas: params.TxGas, GasPrice: b.BaseFee(), Data: nil}), signer, acc1Key)
b.AddTx(tx)
})
- backend.setPendingBlock(pending)
api := NewBlockChainAPI(backend)
blockHashes := make([]common.Hash, genBlocks+1)
ctx := context.Background()
@@ -3175,7 +3169,7 @@ func TestRPCGetBlockOrHeader(t *testing.T) {
}
blockHashes[i] = header.Hash()
}
- pendingHash := pending.Hash()
+ pendingHash := backend.pending.Hash()
var testSuite = []struct {
blockNumber rpc.BlockNumber
@@ -3406,7 +3400,7 @@ func setupReceiptBackend(t *testing.T, genBlocks int) (*testBackend, []common.Ha
},
}
signer = types.LatestSignerForChainID(params.TestChainConfig.ChainID)
- txHashes = make([]common.Hash, genBlocks)
+ txHashes = make([]common.Hash, 0, genBlocks)
)
backend := newTestBackend(t, genBlocks, genesis, beacon.New(ethash.NewFaker()), func(i int, b *core.BlockGen) {
@@ -3416,9 +3410,6 @@ func setupReceiptBackend(t *testing.T, genBlocks int) (*testBackend, []common.Ha
)
b.SetPoS()
switch i {
- case 0:
- // transfer 1000wei
- tx, err = types.SignTx(types.NewTx(&types.LegacyTx{Nonce: uint64(i), To: &acc2Addr, Value: big.NewInt(1000), Gas: params.TxGas, GasPrice: b.BaseFee(), Data: nil}), types.HomesteadSigner{}, acc1Key)
case 1:
// create contract
tx, err = types.SignTx(types.NewTx(&types.LegacyTx{Nonce: uint64(i), To: nil, Gas: 53100, GasPrice: b.BaseFee(), Data: common.FromHex("0x60806040")}), signer, acc1Key)
@@ -3455,13 +3446,16 @@ func setupReceiptBackend(t *testing.T, genBlocks int) (*testBackend, []common.Ha
BlobHashes: []common.Hash{{1}},
Value: new(uint256.Int),
}), signer, acc1Key)
+ default:
+ // transfer 1000wei
+ tx, err = types.SignTx(types.NewTx(&types.LegacyTx{Nonce: uint64(i), To: &acc2Addr, Value: big.NewInt(1000), Gas: params.TxGas, GasPrice: b.BaseFee(), Data: nil}), types.HomesteadSigner{}, acc1Key)
}
if err != nil {
t.Errorf("failed to sign tx: %v", err)
}
if tx != nil {
b.AddTx(tx)
- txHashes[i] = tx.Hash()
+ txHashes = append(txHashes, tx.Hash())
}
})
return backend, txHashes
@@ -3577,6 +3571,11 @@ func TestRPCGetBlockReceipts(t *testing.T) {
test: rpc.BlockNumberOrHashWithNumber(rpc.LatestBlockNumber),
file: "tag-latest",
},
+ // 3. pending tag
+ {
+ test: rpc.BlockNumberOrHashWithNumber(rpc.PendingBlockNumber),
+ file: "tag-pending",
+ },
// 4. block with legacy transfer tx(hash)
{
test: rpc.BlockNumberOrHashWithHash(blockHashes[1], false),
diff --git a/internal/ethapi/testdata/eth_getBlockByNumber-tag-pending-fullTx.json b/internal/ethapi/testdata/eth_getBlockByNumber-tag-pending-fullTx.json
index 60f18bc114..2e323dcfe7 100644
--- a/internal/ethapi/testdata/eth_getBlockByNumber-tag-pending-fullTx.json
+++ b/internal/ethapi/testdata/eth_getBlockByNumber-tag-pending-fullTx.json
@@ -1,49 +1,40 @@
{
- "difficulty": "0x0",
+ "baseFeePerGas": "0xde56ab3",
+ "difficulty": "0x20000",
"extraData": "0x",
- "gasLimit": "0x0",
- "gasUsed": "0x0",
+ "gasLimit": "0x47e7c4",
+ "gasUsed": "0x5208",
"hash": null,
"logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
"miner": null,
"mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
"nonce": null,
"number": "0xb",
- "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
- "receiptsRoot": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
+ "parentHash": "0xa063415a5020f1569fae73ecb0d37bc5649ebe86d59e764a389eb37814bd42cb",
+ "receiptsRoot": "0x056b23fbba480696b65fe5a59b8f2148a1299103c4f57df839233af2cf4ca2d2",
"sha3Uncles": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347",
- "size": "0x256",
- "stateRoot": "0x0000000000000000000000000000000000000000000000000000000000000000",
- "timestamp": "0x2a",
+ "size": "0x26a",
+ "stateRoot": "0xce0e05397e548614a5b93254662174329466f8f4b1b391eb36fec9a7a591e58e",
+ "timestamp": "0x6e",
"transactions": [
{
- "blockHash": "0x6cebd9f966ea686f44b981685e3f0eacea28591a7a86d7fbbe521a86e9f81165",
+ "blockHash": "0xfda6c7cb7a3a712e0c424909a7724cab0448e89e286617fa8d5fd27f63f28bd2",
"blockNumber": "0xb",
- "from": "0x0000000000000000000000000000000000000000",
- "gas": "0x457",
- "gasPrice": "0x2b67",
- "hash": "0x4afee081df5dff7a025964032871f7d4ba4d21baf5f6376a2f4a9f79fc506298",
- "input": "0x111111",
- "nonce": "0xb",
+ "from": "0x703c4b2bd70c169f5717101caee543299fc946c7",
+ "gas": "0x5208",
+ "gasPrice": "0xde56ab3",
+ "hash": "0xd773fbb47ec87b1a958ac16430943ddf2797ecae2b33fe7b16ddb334e30325ed",
+ "input": "0x",
+ "nonce": "0xa",
"to": "0x0d3ab14bbad3d99f4203bd7a11acb94882050e7e",
"transactionIndex": "0x0",
- "value": "0x6f",
+ "value": "0x3e8",
"type": "0x0",
- "chainId": "0x7fffffffffffffee",
- "v": "0x0",
- "r": "0x0",
- "s": "0x0"
+ "v": "0x1c",
+ "r": "0xfa029dacd66238d20cd649fe3b323bb458d2cfa4af7db0ff4f6b3e1039bc320a",
+ "s": "0x52fb4d45c1d623f2f05508bae063a4728761d762ae45b8b0908ffea546f3d95e"
}
],
- "transactionsRoot": "0x98d9f6dd0aa479c0fb448f2627e9f1964aca699fccab8f6e95861547a4699e37",
- "uncles": [],
- "withdrawals": [
- {
- "index": "0x0",
- "validatorIndex": "0x1",
- "address": "0x1234000000000000000000000000000000000000",
- "amount": "0xa"
- }
- ],
- "withdrawalsRoot": "0x73d756269cdfc22e7e17a3548e36f42f750ca06d7e3cd98d1b6d0eb5add9dc84"
+ "transactionsRoot": "0x59abb8ec0655f66e66450d1502618bc64022ae2d2950fa471eec6e8da2846264",
+ "uncles": []
}
\ No newline at end of file
diff --git a/internal/ethapi/testdata/eth_getBlockByNumber-tag-pending.json b/internal/ethapi/testdata/eth_getBlockByNumber-tag-pending.json
index dda2d93213..3254482cd9 100644
--- a/internal/ethapi/testdata/eth_getBlockByNumber-tag-pending.json
+++ b/internal/ethapi/testdata/eth_getBlockByNumber-tag-pending.json
@@ -1,32 +1,24 @@
{
- "difficulty": "0x0",
+ "baseFeePerGas": "0xde56ab3",
+ "difficulty": "0x20000",
"extraData": "0x",
- "gasLimit": "0x0",
- "gasUsed": "0x0",
+ "gasLimit": "0x47e7c4",
+ "gasUsed": "0x5208",
"hash": null,
"logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
"miner": null,
"mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
"nonce": null,
"number": "0xb",
- "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
- "receiptsRoot": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
+ "parentHash": "0xa063415a5020f1569fae73ecb0d37bc5649ebe86d59e764a389eb37814bd42cb",
+ "receiptsRoot": "0x056b23fbba480696b65fe5a59b8f2148a1299103c4f57df839233af2cf4ca2d2",
"sha3Uncles": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347",
- "size": "0x256",
- "stateRoot": "0x0000000000000000000000000000000000000000000000000000000000000000",
- "timestamp": "0x2a",
+ "size": "0x26a",
+ "stateRoot": "0xce0e05397e548614a5b93254662174329466f8f4b1b391eb36fec9a7a591e58e",
+ "timestamp": "0x6e",
"transactions": [
- "0x4afee081df5dff7a025964032871f7d4ba4d21baf5f6376a2f4a9f79fc506298"
+ "0xd773fbb47ec87b1a958ac16430943ddf2797ecae2b33fe7b16ddb334e30325ed"
],
- "transactionsRoot": "0x98d9f6dd0aa479c0fb448f2627e9f1964aca699fccab8f6e95861547a4699e37",
- "uncles": [],
- "withdrawals": [
- {
- "index": "0x0",
- "validatorIndex": "0x1",
- "address": "0x1234000000000000000000000000000000000000",
- "amount": "0xa"
- }
- ],
- "withdrawalsRoot": "0x73d756269cdfc22e7e17a3548e36f42f750ca06d7e3cd98d1b6d0eb5add9dc84"
+ "transactionsRoot": "0x59abb8ec0655f66e66450d1502618bc64022ae2d2950fa471eec6e8da2846264",
+ "uncles": []
}
\ No newline at end of file
diff --git a/internal/ethapi/testdata/eth_getBlockReceipts-tag-pending.json b/internal/ethapi/testdata/eth_getBlockReceipts-tag-pending.json
new file mode 100644
index 0000000000..75f9f3ad99
--- /dev/null
+++ b/internal/ethapi/testdata/eth_getBlockReceipts-tag-pending.json
@@ -0,0 +1,18 @@
+[
+ {
+ "blockHash": "0xc74cf882395ec92eec3673d93a57f9a3bf1a5e696fae3e52f252059af62756c8",
+ "blockNumber": "0x7",
+ "contractAddress": null,
+ "cumulativeGasUsed": "0x5208",
+ "effectiveGasPrice": "0x17b07ddf",
+ "from": "0x703c4b2bd70c169f5717101caee543299fc946c7",
+ "gasUsed": "0x5208",
+ "logs": [],
+ "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
+ "status": "0x1",
+ "to": "0x0d3ab14bbad3d99f4203bd7a11acb94882050e7e",
+ "transactionHash": "0xa7eeffe8111539a8f9725eb4d49e341efa1287d33190300adab220929daa5fac",
+ "transactionIndex": "0x0",
+ "type": "0x0"
+ }
+]
\ No newline at end of file
diff --git a/internal/ethapi/testdata/eth_getHeaderByNumber-tag-pending.json b/internal/ethapi/testdata/eth_getHeaderByNumber-tag-pending.json
index 289ff5fece..e4121824ef 100644
--- a/internal/ethapi/testdata/eth_getHeaderByNumber-tag-pending.json
+++ b/internal/ethapi/testdata/eth_getHeaderByNumber-tag-pending.json
@@ -1,19 +1,19 @@
{
- "difficulty": "0x0",
+ "baseFeePerGas": "0xde56ab3",
+ "difficulty": "0x20000",
"extraData": "0x",
- "gasLimit": "0x0",
- "gasUsed": "0x0",
+ "gasLimit": "0x47e7c4",
+ "gasUsed": "0x5208",
"hash": null,
"logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
"miner": null,
"mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
"nonce": null,
"number": "0xb",
- "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
- "receiptsRoot": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
+ "parentHash": "0xa063415a5020f1569fae73ecb0d37bc5649ebe86d59e764a389eb37814bd42cb",
+ "receiptsRoot": "0x056b23fbba480696b65fe5a59b8f2148a1299103c4f57df839233af2cf4ca2d2",
"sha3Uncles": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347",
- "stateRoot": "0x0000000000000000000000000000000000000000000000000000000000000000",
- "timestamp": "0x2a",
- "transactionsRoot": "0x98d9f6dd0aa479c0fb448f2627e9f1964aca699fccab8f6e95861547a4699e37",
- "withdrawalsRoot": "0x73d756269cdfc22e7e17a3548e36f42f750ca06d7e3cd98d1b6d0eb5add9dc84"
+ "stateRoot": "0xce0e05397e548614a5b93254662174329466f8f4b1b391eb36fec9a7a591e58e",
+ "timestamp": "0x6e",
+ "transactionsRoot": "0x59abb8ec0655f66e66450d1502618bc64022ae2d2950fa471eec6e8da2846264"
}
\ No newline at end of file
diff --git a/internal/web3ext/web3ext.go b/internal/web3ext/web3ext.go
index d7f37a79ee..daef2e32ee 100644
--- a/internal/web3ext/web3ext.go
+++ b/internal/web3ext/web3ext.go
@@ -217,11 +217,6 @@ web3._extend({
call: 'debug_setHead',
params: 1
}),
- new web3._extend.Method({
- name: 'seedHash',
- call: 'debug_seedHash',
- params: 1
- }),
new web3._extend.Method({
name: 'dumpBlock',
call: 'debug_dumpBlock',
diff --git a/metrics/cputime_nop.go b/metrics/cputime_nop.go
index 465d88c4d2..a6285ec10a 100644
--- a/metrics/cputime_nop.go
+++ b/metrics/cputime_nop.go
@@ -14,8 +14,8 @@
// You should have received a copy of the GNU Lesser General Public License
// along with the go-ethereum library. If not, see .
-//go:build windows || js
-// +build windows js
+//go:build windows || js || tinygo
+// +build windows js tinygo
package metrics
diff --git a/metrics/cputime_unix.go b/metrics/cputime_unix.go
index a44bf80876..5db38b16a2 100644
--- a/metrics/cputime_unix.go
+++ b/metrics/cputime_unix.go
@@ -14,8 +14,8 @@
// You should have received a copy of the GNU Lesser General Public License
// along with the go-ethereum library. If not, see .
-//go:build !windows && !js && !wasip1
-// +build !windows,!js,!wasip1
+//go:build !windows && !js && !wasip1 && !tinygo
+// +build !windows,!js,!wasip1,!tinygo
package metrics
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)
}
diff --git a/miner/miner.go b/miner/miner.go
index ddfe0dcf26..20845b5036 100644
--- a/miner/miner.go
+++ b/miner/miner.go
@@ -144,10 +144,10 @@ func (miner *Miner) getPending() *newPayloadResult {
header := miner.chain.CurrentHeader()
miner.pendingMu.Lock()
defer miner.pendingMu.Unlock()
+
if cached := miner.pending.resolve(header.Hash()); cached != nil {
return cached
}
-
var (
timestamp = uint64(time.Now().Unix())
withdrawal types.Withdrawals
diff --git a/miner/worker.go b/miner/worker.go
index ee31a65359..0e2560f844 100644
--- a/miner/worker.go
+++ b/miner/worker.go
@@ -271,7 +271,7 @@ func (miner *Miner) makeEnv(parent *types.Header, header *types.Header, coinbase
if err != nil {
return nil, err
}
- state.StartPrefetcher("miner", bundle)
+ state.StartPrefetcher("miner", bundle, nil)
}
// Note the passed coinbase may be different with header.Coinbase.
return &environment{
@@ -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
}
diff --git a/node/api.go b/node/api.go
index 33dfb3a1cc..e5dda5ac4d 100644
--- a/node/api.go
+++ b/node/api.go
@@ -191,7 +191,7 @@ func (api *adminAPI) StartHTTP(host *string, port *int, cors *string, apis *stri
}
if vhosts != nil {
config.Vhosts = nil
- for _, vhost := range strings.Split(*host, ",") {
+ for _, vhost := range strings.Split(*vhosts, ",") {
config.Vhosts = append(config.Vhosts, strings.TrimSpace(vhost))
}
}
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}
)
diff --git a/p2p/config.go b/p2p/config.go
index 68a9c0bb5f..17607a1f88 100644
--- a/p2p/config.go
+++ b/p2p/config.go
@@ -35,8 +35,7 @@ type Config struct {
// This field must be set to a valid secp256k1 private key.
PrivateKey *ecdsa.PrivateKey `toml:"-"`
- // MaxPeers is the maximum number of peers that can be
- // connected. It must be greater than zero.
+ // MaxPeers is the maximum number of peers that can be connected.
MaxPeers int
// MaxPendingPeers is the maximum number of peers that can be pending in the
diff --git a/p2p/discover/v5_udp_test.go b/p2p/discover/v5_udp_test.go
index 3a384aab12..6abe20d7a4 100644
--- a/p2p/discover/v5_udp_test.go
+++ b/p2p/discover/v5_udp_test.go
@@ -378,9 +378,93 @@ func TestUDPv5_findnodeCall(t *testing.T) {
if !reflect.DeepEqual(response, nodes) {
t.Fatalf("wrong nodes in response")
}
+}
- // TODO: check invalid IPs
- // TODO: check invalid/unsigned record
+// BadIdentityScheme mocks an identity scheme not supported by the test node.
+type BadIdentityScheme struct{}
+
+func (s BadIdentityScheme) Verify(r *enr.Record, sig []byte) error { return nil }
+func (s BadIdentityScheme) NodeAddr(r *enr.Record) []byte {
+ var id enode.ID
+ r.Load(enr.WithEntry("badaddr", &id))
+ return id[:]
+}
+
+// This test covers invalid NODES responses for the FINDNODE call in a single table-driven test.
+func TestUDPv5_findnodeCall_InvalidNodes(t *testing.T) {
+ t.Parallel()
+ test := newUDPV5Test(t)
+ defer test.close()
+
+ for i, tt := range []struct {
+ name string
+ ip enr.Entry
+ port enr.Entry
+ sign func(r *enr.Record, id enode.ID) *enode.Node
+ }{
+ {
+ name: "invalid ip (unspecified 0.0.0.0)",
+ ip: enr.IP(net.IPv4zero),
+ },
+ {
+ name: "invalid udp port (<=1024)",
+ port: enr.UDP(1024),
+ },
+ {
+ name: "invalid record, no signature",
+ sign: func(r *enr.Record, id enode.ID) *enode.Node {
+ r.Set(enr.ID("bad"))
+ r.Set(enr.WithEntry("badaddr", id))
+ r.SetSig(BadIdentityScheme{}, []byte{})
+ n, _ := enode.New(BadIdentityScheme{}, r)
+ return n
+ },
+ },
+ } {
+ t.Run(tt.name, func(t *testing.T) {
+ // Build ENR node for test.
+ var (
+ distance = 230
+ remote = test.getNode(test.remotekey, test.remoteaddr).Node()
+ id = idAtDistance(remote.ID(), distance)
+ r enr.Record
+ )
+ r.Set(enr.IP(intIP(i)))
+ if tt.ip != nil {
+ r.Set(tt.ip)
+ }
+ r.Set(enr.UDP(30303))
+ if tt.port != nil {
+ r.Set(tt.port)
+ }
+ r = *enode.SignNull(&r, id).Record()
+ if tt.sign != nil {
+ r = *tt.sign(&r, id).Record()
+ }
+
+ // Launch findnode request.
+ var (
+ done = make(chan error, 1)
+ got []*enode.Node
+ )
+ go func() {
+ var err error
+ got, err = test.udp.Findnode(remote, []uint{uint(distance)})
+ done <- err
+ }()
+
+ // Handle request.
+ test.waitPacketOut(func(p *v5wire.Findnode, _ netip.AddrPort, _ v5wire.Nonce) {
+ test.packetIn(&v5wire.Nodes{ReqID: p.ReqID, RespCount: 1, Nodes: []*enr.Record{&r}})
+ })
+ if err := <-done; err != nil {
+ t.Fatalf("unexpected error: %v", err)
+ }
+ if len(got) != 0 {
+ t.Fatalf("expected 0 nodes, got %d", len(got))
+ }
+ })
+ }
}
// This test checks that pending calls are re-sent when a handshake happens.
diff --git a/p2p/discover/v5wire/encoding.go b/p2p/discover/v5wire/encoding.go
index ec5ef8a261..08292a70ba 100644
--- a/p2p/discover/v5wire/encoding.go
+++ b/p2p/discover/v5wire/encoding.go
@@ -27,6 +27,7 @@ import (
"errors"
"fmt"
"hash"
+ "slices"
"github.com/ethereum/go-ethereum/common/mclock"
"github.com/ethereum/go-ethereum/p2p/enode"
@@ -222,7 +223,7 @@ func (c *Codec) Encode(id enode.ID, addr string, packet Packet, challenge *Whoar
// Store sent WHOAREYOU challenges.
if challenge, ok := packet.(*Whoareyou); ok {
- challenge.ChallengeData = bytesCopy(&c.buf)
+ challenge.ChallengeData = slices.Clone(c.buf.Bytes())
enc, err := c.EncodeRaw(id, head, msgData)
if err != nil {
return nil, Nonce{}, err
@@ -325,7 +326,7 @@ func (c *Codec) encodeWhoareyou(toID enode.ID, packet *Whoareyou) (Header, error
// Create header.
head := c.makeHeader(toID, flagWhoareyou, 0)
- head.AuthData = bytesCopy(&c.buf)
+ head.AuthData = slices.Clone(c.buf.Bytes())
head.Nonce = packet.Nonce
// Encode auth data.
@@ -430,7 +431,7 @@ func (c *Codec) encodeMessageHeader(toID enode.ID, s *session) (Header, error) {
auth := messageAuthData{SrcID: c.localnode.ID()}
c.buf.Reset()
binary.Write(&c.buf, binary.BigEndian, &auth)
- head.AuthData = bytesCopy(&c.buf)
+ head.AuthData = slices.Clone(c.buf.Bytes())
head.Nonce = nonce
return head, err
}
@@ -686,9 +687,3 @@ func (h *Header) mask(destID enode.ID) cipher.Stream {
}
return cipher.NewCTR(block, h.IV[:])
}
-
-func bytesCopy(r *bytes.Buffer) []byte {
- b := make([]byte, r.Len())
- copy(b, r.Bytes())
- return b
-}
diff --git a/p2p/enode/localnode.go b/p2p/enode/localnode.go
index 6e79c9cbdc..6425560b02 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
}
@@ -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.
diff --git a/p2p/msgrate/msgrate.go b/p2p/msgrate/msgrate.go
index de1a3177db..7702256ed4 100644
--- a/p2p/msgrate/msgrate.go
+++ b/p2p/msgrate/msgrate.go
@@ -171,8 +171,7 @@ func (t *Tracker) Capacity(kind uint64, targetRTT time.Duration) int {
// roundCapacity gives the integer value of a capacity.
// The result fits int32, and is guaranteed to be positive.
func roundCapacity(cap float64) int {
- const maxInt32 = float64(1<<31 - 1)
- return int(math.Min(maxInt32, math.Max(1, math.Ceil(cap))))
+ return int(min(math.MaxInt32, max(1, math.Ceil(cap))))
}
// Update modifies the peer's capacity values for a specific data type with a new
diff --git a/p2p/peer.go b/p2p/peer.go
index 9a0a750ac8..5521889f30 100644
--- a/p2p/peer.go
+++ b/p2p/peer.go
@@ -173,7 +173,6 @@ func (p *Peer) Fullname() string {
// Caps returns the capabilities (supported subprotocols) of the remote peer.
func (p *Peer) Caps() []Cap {
- // TODO: maybe return copy
return p.rw.caps
}
diff --git a/params/protocol_params.go b/params/protocol_params.go
index 2ec3a5c249..e8b044f450 100644
--- a/params/protocol_params.go
+++ b/params/protocol_params.go
@@ -180,7 +180,7 @@ const (
BlobTxMaxBlobs = 6
BlobBaseCost = 1 << 13 // Base execution gas cost for a blob.
- HistoryServeWindow = 8192 // Number of blocks to serve historical block hashes for, EIP-2935.
+ HistoryServeWindow = 8191 // Number of blocks to serve historical block hashes for, EIP-2935.
MaxBlockSize = 8_388_608 // maximum size of an RLP-encoded block
)
diff --git a/rlp/decode.go b/rlp/decode.go
index 0fbca243ee..19074072fb 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) {
@@ -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 {
@@ -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/encbuffer.go b/rlp/encbuffer.go
index 8d3a3b2293..61d8bd059c 100644
--- a/rlp/encbuffer.go
+++ b/rlp/encbuffer.go
@@ -23,6 +23,7 @@ import (
"reflect"
"sync"
+ "github.com/ethereum/go-ethereum/common/math"
"github.com/holiman/uint256"
)
@@ -145,9 +146,6 @@ func (buf *encBuffer) writeString(s string) {
buf.writeBytes([]byte(s))
}
-// wordBytes is the number of bytes in a big.Word
-const wordBytes = (32 << (uint64(^big.Word(0)) >> 63)) / 8
-
// writeBigInt writes i as an integer.
func (buf *encBuffer) writeBigInt(i *big.Int) {
bitlen := i.BitLen()
@@ -161,15 +159,8 @@ func (buf *encBuffer) writeBigInt(i *big.Int) {
length := ((bitlen + 7) & -8) >> 3
buf.encodeStringHeader(length)
buf.str = append(buf.str, make([]byte, length)...)
- index := length
bytesBuf := buf.str[len(buf.str)-length:]
- for _, d := range i.Bits() {
- for j := 0; j < wordBytes && index > 0; j++ {
- index--
- bytesBuf[index] = byte(d)
- d >>= 8
- }
- }
+ math.ReadBits(i, bytesBuf)
}
// writeUint256 writes z as an integer.
diff --git a/rlp/encode.go b/rlp/encode.go
index 3645bbfda0..ed99275739 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"
@@ -133,7 +134,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) {
@@ -239,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
@@ -248,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
@@ -487,9 +487,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
}
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 {
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/rpc/server.go b/rpc/server.go
index 42b59f8f6f..599e31fb41 100644
--- a/rpc/server.go
+++ b/rpc/server.go
@@ -54,6 +54,7 @@ type Server struct {
batchItemLimit int
batchResponseLimit int
httpBodyLimit int
+ wsReadLimit int64
}
// NewServer creates a new server instance with no registered handlers.
@@ -62,6 +63,7 @@ func NewServer() *Server {
idgen: randomIDGenerator(),
codecs: make(map[ServerCodec]struct{}),
httpBodyLimit: defaultBodyLimit,
+ wsReadLimit: wsDefaultReadLimit,
}
server.run.Store(true)
// Register the default service providing meta information about the RPC service such
@@ -89,6 +91,13 @@ func (s *Server) SetHTTPBodyLimit(limit int) {
s.httpBodyLimit = limit
}
+// SetWebsocketReadLimit sets the limit for max message size for Websocket requests.
+//
+// This method should be called before processing any requests via Websocket server.
+func (s *Server) SetWebsocketReadLimit(limit int64) {
+ s.wsReadLimit = limit
+}
+
// RegisterName creates a service for the given receiver type under the given name. When no
// methods on the given receiver match the criteria to be either an RPC method or a
// subscription an error is returned. Otherwise a new service is created and added to the
diff --git a/rpc/server_test.go b/rpc/server_test.go
index 9ee545d81a..a38a64b080 100644
--- a/rpc/server_test.go
+++ b/rpc/server_test.go
@@ -19,13 +19,18 @@ package rpc
import (
"bufio"
"bytes"
+ "context"
+ "errors"
"io"
"net"
+ "net/http/httptest"
"os"
"path/filepath"
"strings"
"testing"
"time"
+
+ "github.com/gorilla/websocket"
)
func TestServerRegisterName(t *testing.T) {
@@ -202,3 +207,86 @@ func TestServerBatchResponseSizeLimit(t *testing.T) {
}
}
}
+
+func TestServerWebsocketReadLimit(t *testing.T) {
+ t.Parallel()
+
+ // Test different read limits
+ testCases := []struct {
+ name string
+ readLimit int64
+ testSize int
+ shouldFail bool
+ }{
+ {
+ name: "limit with small request - should succeed",
+ readLimit: 4096, // generous limit to comfortably allow JSON overhead
+ testSize: 256, // reasonably small payload
+ shouldFail: false,
+ },
+ {
+ name: "limit with large request - should fail",
+ readLimit: 256, // tight limit to trigger server-side read limit
+ testSize: 1024, // payload that will exceed the limit including JSON overhead
+ shouldFail: true,
+ },
+ }
+
+ for _, tc := range testCases {
+ t.Run(tc.name, func(t *testing.T) {
+ // Create server and set read limits
+ srv := newTestServer()
+ srv.SetWebsocketReadLimit(tc.readLimit)
+ defer srv.Stop()
+
+ // Start HTTP server with WebSocket handler
+ httpsrv := httptest.NewServer(srv.WebsocketHandler([]string{"*"}))
+ defer httpsrv.Close()
+
+ wsURL := "ws:" + strings.TrimPrefix(httpsrv.URL, "http:")
+
+ // Connect WebSocket client
+ client, err := DialOptions(context.Background(), wsURL)
+ if err != nil {
+ t.Fatalf("can't dial: %v", err)
+ }
+ defer client.Close()
+
+ // Create large request data - this is what will be limited
+ largeString := strings.Repeat("A", tc.testSize)
+
+ // Send the large string as a parameter in the request
+ var result echoResult
+ err = client.Call(&result, "test_echo", largeString, 42, &echoArgs{S: "test"})
+
+ if tc.shouldFail {
+ // Expecting an error due to read limit exceeded
+ if err == nil {
+ t.Fatalf("expected error for request size %d with limit %d, but got none", tc.testSize, tc.readLimit)
+ }
+ // Be tolerant about the exact error surfaced by gorilla/websocket.
+ // Prefer a CloseError with code 1009, but accept ErrReadLimit or an error string containing 1009/message too big.
+ var cerr *websocket.CloseError
+ if errors.As(err, &cerr) {
+ if cerr.Code != websocket.CloseMessageTooBig {
+ t.Fatalf("unexpected websocket close code: have %d want %d (err=%v)", cerr.Code, websocket.CloseMessageTooBig, err)
+ }
+ } else if !errors.Is(err, websocket.ErrReadLimit) &&
+ !strings.Contains(strings.ToLower(err.Error()), "1009") &&
+ !strings.Contains(strings.ToLower(err.Error()), "message too big") {
+ // Not the error we expect from exceeding the message size limit.
+ t.Fatalf("unexpected error for read limit violation: %v", err)
+ }
+ } else {
+ // Expecting success
+ if err != nil {
+ t.Fatalf("unexpected error for request size %d with limit %d: %v", tc.testSize, tc.readLimit, err)
+ }
+ // Verify the response is correct - the echo should return our string
+ if result.String != largeString {
+ t.Fatalf("expected echo result to match input")
+ }
+ }
+ })
+ }
+}
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 {
diff --git a/rpc/websocket.go b/rpc/websocket.go
index 9f67caf859..543ff617ba 100644
--- a/rpc/websocket.go
+++ b/rpc/websocket.go
@@ -60,7 +60,7 @@ func (s *Server) WebsocketHandler(allowedOrigins []string) http.Handler {
log.Debug("WebSocket upgrade failed", "err", err)
return
}
- codec := newWebsocketCodec(conn, r.Host, r.Header, wsDefaultReadLimit)
+ codec := newWebsocketCodec(conn, r.Host, r.Header, s.wsReadLimit)
s.ServeCodec(codec, 0)
})
}
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
}
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/secure_trie.go b/trie/secure_trie.go
index 0424ecb6e5..7c7bd184bf 100644
--- a/trie/secure_trie.go
+++ b/trie/secure_trie.go
@@ -105,19 +105,6 @@ func (t *StateTrie) MustGet(key []byte) []byte {
return t.trie.MustGet(crypto.Keccak256(key))
}
-// GetStorage attempts to retrieve a storage slot with provided account address
-// and slot key. The value bytes must not be modified by the caller.
-// If the specified storage slot is not in the trie, nil will be returned.
-// If a trie node is not found in the database, a MissingNodeError is returned.
-func (t *StateTrie) GetStorage(_ common.Address, key []byte) ([]byte, error) {
- enc, err := t.trie.Get(crypto.Keccak256(key))
- if err != nil || len(enc) == 0 {
- return nil, err
- }
- _, content, _, err := rlp.Split(enc)
- return content, err
-}
-
// GetAccount attempts to retrieve an account with provided account address.
// If the specified account is not in the trie, nil will be returned.
// If a trie node is not found in the database, a MissingNodeError is returned.
@@ -144,6 +131,39 @@ func (t *StateTrie) GetAccountByHash(addrHash common.Hash) (*types.StateAccount,
return ret, err
}
+// PrefetchAccount attempts to resolve specific accounts from the database
+// to accelerate subsequent trie operations.
+func (t *StateTrie) PrefetchAccount(addresses []common.Address) error {
+ var keys [][]byte
+ for _, addr := range addresses {
+ keys = append(keys, crypto.Keccak256(addr.Bytes()))
+ }
+ return t.trie.Prefetch(keys)
+}
+
+// GetStorage attempts to retrieve a storage slot with provided account address
+// and slot key. The value bytes must not be modified by the caller.
+// If the specified storage slot is not in the trie, nil will be returned.
+// If a trie node is not found in the database, a MissingNodeError is returned.
+func (t *StateTrie) GetStorage(_ common.Address, key []byte) ([]byte, error) {
+ enc, err := t.trie.Get(crypto.Keccak256(key))
+ if err != nil || len(enc) == 0 {
+ return nil, err
+ }
+ _, content, _, err := rlp.Split(enc)
+ return content, err
+}
+
+// PrefetchStorage attempts to resolve specific storage slots from the database
+// to accelerate subsequent trie operations.
+func (t *StateTrie) PrefetchStorage(_ common.Address, keys [][]byte) error {
+ var keylist [][]byte
+ for _, key := range keys {
+ keylist = append(keylist, crypto.Keccak256(key))
+ }
+ return t.trie.Prefetch(keylist)
+}
+
// GetNode attempts to retrieve a trie node by compact-encoded path. It is not
// possible to use keybyte-encoding as the path might contain odd nibbles.
// If the specified trie node is not in the trie, nil will be returned.
@@ -253,7 +273,7 @@ func (t *StateTrie) GetKey(shaKey []byte) []byte {
}
// Witness returns a set containing all trie nodes that have been accessed.
-func (t *StateTrie) Witness() map[string]struct{} {
+func (t *StateTrie) Witness() map[string][]byte {
return t.trie.Witness()
}
diff --git a/trie/tracer.go b/trie/tracer.go
index 90b9666f0b..b0542404a7 100644
--- a/trie/tracer.go
+++ b/trie/tracer.go
@@ -18,14 +18,13 @@ package trie
import (
"maps"
-
- "github.com/ethereum/go-ethereum/common"
+ "sync"
)
-// 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,102 @@ 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
+ lock sync.RWMutex
+}
+
+// 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.lock.Lock()
+ defer t.lock.Unlock()
+
+ 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 {
+ t.lock.RLock()
+ defer t.lock.RUnlock()
+
+ 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 {
+ t.lock.RLock()
+ defer t.lock.RUnlock()
+
+ 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() map[string][]byte {
+ t.lock.RLock()
+ defer t.lock.RUnlock()
+
+ return maps.Clone(t.data)
+}
+
+// reset resets the cached content in the prevalueTracer.
+func (t *prevalueTracer) reset() {
+ t.lock.Lock()
+ defer t.lock.Unlock()
+
+ clear(t.data)
+}
+
+// copy returns a copied prevalueTracer instance.
+func (t *prevalueTracer) copy() *prevalueTracer {
+ t.lock.RLock()
+ defer t.lock.RUnlock()
+
+ // 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..695570fd0d 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,8 @@ 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 +86,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 +97,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 +112,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 +210,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 +249,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/transition.go b/trie/transition.go
new file mode 100644
index 0000000000..da49c6cdc2
--- /dev/null
+++ b/trie/transition.go
@@ -0,0 +1,227 @@
+// 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 NewTransitionTrie(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)
+}
+
+// PrefetchStorage attempts to resolve specific storage slots from the database
+// to accelerate subsequent trie operations.
+func (t *TransitionTrie) PrefetchStorage(addr common.Address, keys [][]byte) error {
+ for _, key := range keys {
+ if _, err := t.GetStorage(addr, key); err != nil {
+ return err
+ }
+ }
+ return nil
+}
+
+// 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)
+}
+
+// PrefetchAccount attempts to resolve specific accounts from the database
+// to accelerate subsequent trie operations.
+func (t *TransitionTrie) PrefetchAccount(addresses []common.Address) error {
+ for _, addr := range addresses {
+ if _, err := t.GetAccount(addr); err != nil {
+ return err
+ }
+ }
+ return nil
+}
+
+// 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
+}
+
+// UpdateStem 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][]byte {
+ panic("not implemented")
+}
diff --git a/trie/trie.go b/trie/trie.go
index 222bf8b1f0..98cf751f47 100644
--- a/trie/trie.go
+++ b/trie/trie.go
@@ -21,12 +21,14 @@ import (
"bytes"
"errors"
"fmt"
+ "slices"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/trie/trienode"
"github.com/ethereum/go-ethereum/triedb/database"
+ "golang.org/x/sync/errgroup"
)
// Trie represents a Merkle Patricia Trie. Use New to create a trie that operates
@@ -55,8 +57,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 +70,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 +93,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)
@@ -190,6 +195,51 @@ func (t *Trie) get(origNode node, key []byte, pos int) (value []byte, newnode no
}
}
+// Prefetch attempts to resolve the leaves and intermediate trie nodes
+// specified by the key list in parallel. The results are silently
+// discarded to simplify the function.
+func (t *Trie) Prefetch(keylist [][]byte) error {
+ // Short circuit if the trie is already committed and not usable.
+ if t.committed {
+ return ErrCommitted
+ }
+ // Resolve the trie nodes sequentially if there are not too many
+ // trie nodes in the trie.
+ fn, ok := t.root.(*fullNode)
+ if !ok || len(keylist) < 16 {
+ for _, key := range keylist {
+ _, err := t.Get(key)
+ if err != nil {
+ return err
+ }
+ }
+ return nil
+ }
+ var (
+ keys = make(map[byte][][]byte)
+ eg errgroup.Group
+ )
+ for _, key := range keylist {
+ hkey := keybytesToHex(key)
+ keys[hkey[0]] = append(keys[hkey[0]], hkey)
+ }
+ for pos, ks := range keys {
+ eg.Go(func() error {
+ for _, k := range ks {
+ _, newnode, didResolve, err := t.get(fn.Children[pos], k, 1)
+ if err == nil && didResolve {
+ fn.Children[pos] = newnode
+ }
+ if err != nil {
+ return err
+ }
+ }
+ return nil
+ })
+ }
+ return eg.Wait()
+}
+
// MustGetNode is a wrapper of GetNode and will omit any encountered error but
// just print out an error message.
func (t *Trie) MustGetNode(path []byte) ([]byte, int) {
@@ -361,7 +411,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 +429,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 +494,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 +510,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
@@ -468,7 +518,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
}
@@ -525,7 +575,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
@@ -563,13 +613,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) {
@@ -616,13 +659,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 +705,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 +728,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
}
@@ -691,15 +752,8 @@ 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 {
- return nil
- }
- witness := make(map[string]struct{}, len(t.tracer.accessList))
- for _, node := range t.tracer.accessList {
- witness[string(node)] = struct{}{}
- }
- return witness
+func (t *Trie) Witness() map[string][]byte {
+ return t.prevalueTracer.values()
}
// Reset drops the referenced root node and cleans all internal state.
@@ -708,6 +762,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..22c3494f47 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")
}
@@ -1499,3 +1499,83 @@ func testTrieCopyNewTrie(t *testing.T, entries []kv) {
t.Errorf("Hash mismatch: old %v, new %v", hash, tr.Hash())
}
}
+
+// goos: darwin
+// goarch: arm64
+// pkg: github.com/ethereum/go-ethereum/trie
+// cpu: Apple M1 Pro
+// BenchmarkTriePrefetch
+// BenchmarkTriePrefetch-8 9961 100706 ns/op
+func BenchmarkTriePrefetch(b *testing.B) {
+ db := newTestDatabase(rawdb.NewMemoryDatabase(), rawdb.HashScheme)
+ tr := NewEmpty(db)
+ vals := make(map[string]*kv)
+ for i := 0; i < 3000; i++ {
+ value := &kv{
+ k: randBytes(32),
+ v: randBytes(20),
+ t: false,
+ }
+ tr.MustUpdate(value.k, value.v)
+ vals[string(value.k)] = value
+ }
+ root, nodes := tr.Commit(false)
+ db.Update(root, types.EmptyRootHash, trienode.NewWithNodeSet(nodes))
+ b.ResetTimer()
+
+ for i := 0; i < b.N; i++ {
+ tr, err := New(TrieID(root), db)
+ if err != nil {
+ b.Fatalf("Failed to open the trie")
+ }
+ var keys [][]byte
+ for k := range vals {
+ keys = append(keys, []byte(k))
+ if len(keys) > 64 {
+ break
+ }
+ }
+ tr.Prefetch(keys)
+ }
+}
+
+// goos: darwin
+// goarch: arm64
+// pkg: github.com/ethereum/go-ethereum/trie
+// cpu: Apple M1 Pro
+// BenchmarkTrieSeqPrefetch
+// BenchmarkTrieSeqPrefetch-8 12879 96710 ns/op
+func BenchmarkTrieSeqPrefetch(b *testing.B) {
+ db := newTestDatabase(rawdb.NewMemoryDatabase(), rawdb.HashScheme)
+ tr := NewEmpty(db)
+ vals := make(map[string]*kv)
+ for i := 0; i < 3000; i++ {
+ value := &kv{
+ k: randBytes(32),
+ v: randBytes(20),
+ t: false,
+ }
+ tr.MustUpdate(value.k, value.v)
+ vals[string(value.k)] = value
+ }
+ root, nodes := tr.Commit(false)
+ db.Update(root, types.EmptyRootHash, trienode.NewWithNodeSet(nodes))
+ b.ResetTimer()
+
+ for i := 0; i < b.N; i++ {
+ tr, err := New(TrieID(root), db)
+ if err != nil {
+ b.Fatalf("Failed to open the trie")
+ }
+ var keys [][]byte
+ for k := range vals {
+ keys = append(keys, []byte(k))
+ if len(keys) > 64 {
+ break
+ }
+ }
+ for _, k := range keys {
+ tr.Get(k)
+ }
+ }
+}
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..e00ea21602 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
@@ -109,6 +108,17 @@ func (t *VerkleTrie) GetAccount(addr common.Address) (*types.StateAccount, error
return acc, nil
}
+// PrefetchAccount attempts to resolve specific accounts from the database
+// to accelerate subsequent trie operations.
+func (t *VerkleTrie) PrefetchAccount(addresses []common.Address) error {
+ for _, addr := range addresses {
+ if _, err := t.GetAccount(addr); err != nil {
+ return err
+ }
+ }
+ return nil
+}
+
// GetStorage implements state.Trie, retrieving the storage slot with the specified
// account address and storage key. If the specified slot is not in the verkle tree,
// nil will be returned. If the tree is corrupted, an error will be returned.
@@ -121,6 +131,17 @@ func (t *VerkleTrie) GetStorage(addr common.Address, key []byte) ([]byte, error)
return common.TrimLeftZeroes(val), nil
}
+// PrefetchStorage attempts to resolve specific storage slots from the database
+// to accelerate subsequent trie operations.
+func (t *VerkleTrie) PrefetchStorage(addr common.Address, keys [][]byte) error {
+ for _, key := range keys {
+ if _, err := t.GetStorage(addr, key); err != nil {
+ return err
+ }
+ }
+ return nil
+}
+
// UpdateAccount implements state.Trie, writing the provided account into the tree.
// If the tree is corrupted, an error will be returned.
func (t *VerkleTrie) UpdateAccount(addr common.Address, acc *types.StateAccount, codeLen int) error {
@@ -268,7 +289,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 +322,7 @@ func (t *VerkleTrie) Copy() *VerkleTrie {
root: t.root.Copy(),
cache: t.cache,
reader: t.reader,
+ tracer: t.tracer.copy(),
}
}
@@ -317,7 +339,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,10 +443,15 @@ 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.
-func (t *VerkleTrie) Witness() map[string]struct{} {
+func (t *VerkleTrie) Witness() map[string][]byte {
panic("not implemented")
}
diff --git a/triedb/pathdb/database.go b/triedb/pathdb/database.go
index e323a7449e..0a021aea77 100644
--- a/triedb/pathdb/database.go
+++ b/triedb/pathdb/database.go
@@ -219,12 +219,14 @@ type Database struct {
isVerkle bool // Flag if database is used for verkle tree
hasher nodeHasher // Trie node hasher
- config *Config // Configuration for database
- diskdb ethdb.Database // Persistent storage for matured trie nodes
- tree *layerTree // The group for all known layers
- freezer ethdb.ResettableAncientStore // Freezer for storing trie histories, nil possible in tests
- lock sync.RWMutex // Lock to prevent mutations from happening at the same time
- indexer *historyIndexer // History indexer
+ config *Config // Configuration for database
+ diskdb ethdb.Database // Persistent storage for matured trie nodes
+ tree *layerTree // The group for all known layers
+
+ stateFreezer ethdb.ResettableAncientStore // Freezer for storing state histories, nil possible in tests
+ stateIndexer *historyIndexer // History indexer historical state data, nil possible
+
+ lock sync.RWMutex // Lock to prevent mutations from happening at the same time
}
// New attempts to load an already existing layer from a persistent key-value
@@ -275,8 +277,8 @@ func New(diskdb ethdb.Database, config *Config, isVerkle bool) *Database {
log.Crit("Failed to setup the generator", "err", err)
}
// TODO (rjl493456442) disable the background indexing in read-only mode
- if db.freezer != nil && db.config.EnableStateIndexing {
- db.indexer = newHistoryIndexer(db.diskdb, db.freezer, db.tree.bottom().stateID())
+ if db.stateFreezer != nil && db.config.EnableStateIndexing {
+ db.stateIndexer = newHistoryIndexer(db.diskdb, db.stateFreezer, db.tree.bottom().stateID())
log.Info("Enabled state history indexing")
}
fields := config.fields()
@@ -304,14 +306,14 @@ func (db *Database) repairHistory() error {
if err != nil {
log.Crit("Failed to open state history freezer", "err", err)
}
- db.freezer = freezer
+ db.stateFreezer = freezer
// Reset the entire state histories if the trie database is not initialized
// yet. This action is necessary because these state histories are not
// expected to exist without an initialized trie database.
id := db.tree.bottom().stateID()
if id == 0 {
- frozen, err := db.freezer.Ancients()
+ frozen, err := db.stateFreezer.Ancients()
if err != nil {
log.Crit("Failed to retrieve head of state history", "err", err)
}
@@ -321,7 +323,7 @@ func (db *Database) repairHistory() error {
// Purge all state history indexing data first
rawdb.DeleteStateHistoryIndexMetadata(db.diskdb)
rawdb.DeleteStateHistoryIndex(db.diskdb)
- err := db.freezer.Reset()
+ err := db.stateFreezer.Reset()
if err != nil {
log.Crit("Failed to reset state histories", "err", err)
}
@@ -331,7 +333,7 @@ func (db *Database) repairHistory() error {
}
// Truncate the extra state histories above in freezer in case it's not
// aligned with the disk layer. It might happen after a unclean shutdown.
- pruned, err := truncateFromHead(db.diskdb, db.freezer, id)
+ pruned, err := truncateFromHead(db.diskdb, db.stateFreezer, id)
if err != nil {
log.Crit("Failed to truncate extra state histories", "err", err)
}
@@ -507,13 +509,13 @@ func (db *Database) Enable(root common.Hash) error {
// all root->id mappings should be removed as well. Since
// mappings can be huge and might take a while to clear
// them, just leave them in disk and wait for overwriting.
- if db.freezer != nil {
+ if db.stateFreezer != nil {
// TODO(rjl493456442) would be better to group them into a batch.
//
// Purge all state history indexing data first
rawdb.DeleteStateHistoryIndexMetadata(db.diskdb)
rawdb.DeleteStateHistoryIndex(db.diskdb)
- if err := db.freezer.Reset(); err != nil {
+ if err := db.stateFreezer.Reset(); err != nil {
return err
}
}
@@ -529,9 +531,9 @@ func (db *Database) Enable(root common.Hash) error {
// To ensure the history indexer always matches the current state, we must:
// 1. Close any existing indexer
// 2. Re-initialize the indexer so it starts indexing from the new state root.
- if db.indexer != nil && db.freezer != nil && db.config.EnableStateIndexing {
- db.indexer.close()
- db.indexer = newHistoryIndexer(db.diskdb, db.freezer, db.tree.bottom().stateID())
+ if db.stateIndexer != nil && db.stateFreezer != nil && db.config.EnableStateIndexing {
+ db.stateIndexer.close()
+ db.stateIndexer = newHistoryIndexer(db.diskdb, db.stateFreezer, db.tree.bottom().stateID())
log.Info("Re-enabled state history indexing")
}
log.Info("Rebuilt trie database", "root", root)
@@ -551,7 +553,7 @@ func (db *Database) Recover(root common.Hash) error {
if err := db.modifyAllowed(); err != nil {
return err
}
- if db.freezer == nil {
+ if db.stateFreezer == nil {
return errors.New("state rollback is non-supported")
}
// Short circuit if the target state is not recoverable
@@ -564,7 +566,7 @@ func (db *Database) Recover(root common.Hash) error {
dl = db.tree.bottom()
)
for dl.rootHash() != root {
- h, err := readHistory(db.freezer, dl.stateID())
+ h, err := readStateHistory(db.stateFreezer, dl.stateID())
if err != nil {
return err
}
@@ -585,7 +587,7 @@ func (db *Database) Recover(root common.Hash) error {
if err := db.diskdb.SyncKeyValue(); err != nil {
return err
}
- _, err := truncateFromHead(db.diskdb, db.freezer, dl.stateID())
+ _, err := truncateFromHead(db.diskdb, db.stateFreezer, dl.stateID())
if err != nil {
return err
}
@@ -613,12 +615,12 @@ func (db *Database) Recoverable(root common.Hash) bool {
// dev mode. As a consequence, the Pathdb loses the ability for deep reorg
// in certain cases.
// TODO(rjl493456442): Implement the in-memory ancient store.
- if db.freezer == nil {
+ if db.stateFreezer == nil {
return false
}
// Ensure the requested state is a canonical state and all state
// histories in range [id+1, disklayer.ID] are present and complete.
- return checkHistories(db.freezer, *id+1, dl.stateID()-*id, func(m *meta) error {
+ return checkStateHistories(db.stateFreezer, *id+1, dl.stateID()-*id, func(m *meta) error {
if m.parent != root {
return errors.New("unexpected state history")
}
@@ -646,14 +648,14 @@ func (db *Database) Close() error {
dl.resetCache() // release the memory held by clean cache
// Terminate the background state history indexer
- if db.indexer != nil {
- db.indexer.close()
+ if db.stateIndexer != nil {
+ db.stateIndexer.close()
}
// Close the attached state history freezer.
- if db.freezer == nil {
+ if db.stateFreezer == nil {
return nil
}
- return db.freezer.Close()
+ return db.stateFreezer.Close()
}
// Size returns the current storage size of the memory cache in front of the
@@ -704,7 +706,7 @@ func (db *Database) journalPath() string {
// End: State ID of the last history for the query. 0 implies the last available
// object is selected as the ending point. Note end is included in the query.
func (db *Database) AccountHistory(address common.Address, start, end uint64) (*HistoryStats, error) {
- return accountHistory(db.freezer, address, start, end)
+ return accountHistory(db.stateFreezer, address, start, end)
}
// StorageHistory inspects the storage history within the specified range.
@@ -717,22 +719,22 @@ func (db *Database) AccountHistory(address common.Address, start, end uint64) (*
//
// Note, slot refers to the hash of the raw slot key.
func (db *Database) StorageHistory(address common.Address, slot common.Hash, start uint64, end uint64) (*HistoryStats, error) {
- return storageHistory(db.freezer, address, slot, start, end)
+ return storageHistory(db.stateFreezer, address, slot, start, end)
}
// HistoryRange returns the block numbers associated with earliest and latest
// state history in the local store.
func (db *Database) HistoryRange() (uint64, uint64, error) {
- return historyRange(db.freezer)
+ return historyRange(db.stateFreezer)
}
// IndexProgress returns the indexing progress made so far. It provides the
// number of states that remain unindexed.
func (db *Database) IndexProgress() (uint64, error) {
- if db.indexer == nil {
+ if db.stateIndexer == nil {
return 0, nil
}
- return db.indexer.progress()
+ return db.stateIndexer.progress()
}
// AccountIterator creates a new account iterator for the specified root hash and
diff --git a/triedb/pathdb/database_test.go b/triedb/pathdb/database_test.go
index e9a1850ee0..47d13e54a4 100644
--- a/triedb/pathdb/database_test.go
+++ b/triedb/pathdb/database_test.go
@@ -426,7 +426,7 @@ func (t *tester) verifyHistory() error {
for i, root := range t.roots {
// The state history related to the state above disk layer should not exist.
if i > bottom {
- _, err := readHistory(t.db.freezer, uint64(i+1))
+ _, err := readStateHistory(t.db.stateFreezer, uint64(i+1))
if err == nil {
return errors.New("unexpected state history")
}
@@ -434,7 +434,7 @@ func (t *tester) verifyHistory() error {
}
// The state history related to the state below or equal to the disk layer
// should exist.
- obj, err := readHistory(t.db.freezer, uint64(i+1))
+ obj, err := readStateHistory(t.db.stateFreezer, uint64(i+1))
if err != nil {
return err
}
@@ -568,7 +568,7 @@ func TestDisable(t *testing.T) {
t.Fatal("Failed to clean journal")
}
// Ensure all trie histories are removed
- n, err := tester.db.freezer.Ancients()
+ n, err := tester.db.stateFreezer.Ancients()
if err != nil {
t.Fatal("Failed to clean state history")
}
@@ -724,7 +724,7 @@ func TestTailTruncateHistory(t *testing.T) {
tester.db.Close()
tester.db = New(tester.db.diskdb, &Config{StateHistory: 10}, false)
- head, err := tester.db.freezer.Ancients()
+ head, err := tester.db.stateFreezer.Ancients()
if err != nil {
t.Fatalf("Failed to obtain freezer head")
}
diff --git a/triedb/pathdb/disklayer.go b/triedb/pathdb/disklayer.go
index 06f0a7285f..cffe729299 100644
--- a/triedb/pathdb/disklayer.go
+++ b/triedb/pathdb/disklayer.go
@@ -337,16 +337,16 @@ func (dl *diskLayer) commit(bottom *diffLayer, force bool) (*diskLayer, error) {
overflow bool
oldest uint64
)
- if dl.db.freezer != nil {
+ if dl.db.stateFreezer != nil {
// Bail out with an error if writing the state history fails.
// This can happen, for example, if the device is full.
- err := writeHistory(dl.db.freezer, bottom)
+ err := writeStateHistory(dl.db.stateFreezer, bottom)
if err != nil {
return nil, err
}
// Determine if the persisted history object has exceeded the configured
// limitation, set the overflow as true if so.
- tail, err := dl.db.freezer.Tail()
+ tail, err := dl.db.stateFreezer.Tail()
if err != nil {
return nil, err
}
@@ -356,8 +356,8 @@ func (dl *diskLayer) commit(bottom *diffLayer, force bool) (*diskLayer, error) {
oldest = bottom.stateID() - limit + 1 // track the id of history **after truncation**
}
// Notify the state history indexer for newly created history
- if dl.db.indexer != nil {
- if err := dl.db.indexer.extend(bottom.stateID()); err != nil {
+ if dl.db.stateIndexer != nil {
+ if err := dl.db.stateIndexer.extend(bottom.stateID()); err != nil {
return nil, err
}
}
@@ -418,7 +418,7 @@ func (dl *diskLayer) commit(bottom *diffLayer, force bool) (*diskLayer, error) {
// Freeze the live buffer and schedule background flushing
dl.frozen = combined
- dl.frozen.flush(bottom.root, dl.db.diskdb, dl.db.freezer, progress, dl.nodes, dl.states, bottom.stateID(), func() {
+ dl.frozen.flush(bottom.root, dl.db.diskdb, dl.db.stateFreezer, progress, dl.nodes, dl.states, bottom.stateID(), func() {
// Resume the background generation if it's not completed yet.
// The generator is assumed to be available if the progress is
// not nil.
@@ -448,7 +448,7 @@ func (dl *diskLayer) commit(bottom *diffLayer, force bool) (*diskLayer, error) {
// To remove outdated history objects from the end, we set the 'tail' parameter
// to 'oldest-1' due to the offset between the freezer index and the history ID.
if overflow {
- pruned, err := truncateFromTail(ndl.db.diskdb, ndl.db.freezer, oldest-1)
+ pruned, err := truncateFromTail(ndl.db.diskdb, ndl.db.stateFreezer, oldest-1)
if err != nil {
return nil, err
}
@@ -458,7 +458,7 @@ func (dl *diskLayer) commit(bottom *diffLayer, force bool) (*diskLayer, error) {
}
// revert applies the given state history and return a reverted disk layer.
-func (dl *diskLayer) revert(h *history) (*diskLayer, error) {
+func (dl *diskLayer) revert(h *stateHistory) (*diskLayer, error) {
start := time.Now()
if h.meta.root != dl.rootHash() {
return nil, errUnexpectedHistory
@@ -484,8 +484,8 @@ func (dl *diskLayer) revert(h *history) (*diskLayer, error) {
dl.stale = true
// Unindex the corresponding state history
- if dl.db.indexer != nil {
- if err := dl.db.indexer.shorten(dl.id); err != nil {
+ if dl.db.stateIndexer != nil {
+ if err := dl.db.stateIndexer.shorten(dl.id); err != nil {
return nil, err
}
}
diff --git a/triedb/pathdb/history_index_test.go b/triedb/pathdb/history_index_test.go
index 7b24b86fd6..c83c33ffbd 100644
--- a/triedb/pathdb/history_index_test.go
+++ b/triedb/pathdb/history_index_test.go
@@ -180,7 +180,7 @@ func TestBatchIndexerWrite(t *testing.T) {
var (
db = rawdb.NewMemoryDatabase()
batch = newBatchIndexer(db, false)
- histories = makeHistories(10)
+ histories = makeStateHistories(10)
)
for i, h := range histories {
if err := batch.process(h, uint64(i+1)); err != nil {
@@ -257,7 +257,7 @@ func TestBatchIndexerDelete(t *testing.T) {
var (
db = rawdb.NewMemoryDatabase()
bw = newBatchIndexer(db, false)
- histories = makeHistories(10)
+ histories = makeStateHistories(10)
)
// Index histories
for i, h := range histories {
diff --git a/triedb/pathdb/history_indexer.go b/triedb/pathdb/history_indexer.go
index 054d43e946..bb6a4f80c4 100644
--- a/triedb/pathdb/history_indexer.go
+++ b/triedb/pathdb/history_indexer.go
@@ -93,7 +93,7 @@ func newBatchIndexer(db ethdb.KeyValueStore, delete bool) *batchIndexer {
// process iterates through the accounts and their associated storage slots in the
// state history, tracking the mapping between state and history IDs.
-func (b *batchIndexer) process(h *history, historyID uint64) error {
+func (b *batchIndexer) process(h *stateHistory, historyID uint64) error {
for _, address := range h.accountList {
addrHash := crypto.Keccak256Hash(address.Bytes())
b.counter += 1
@@ -241,7 +241,7 @@ func indexSingle(historyID uint64, db ethdb.KeyValueStore, freezer ethdb.Ancient
}
return fmt.Errorf("history indexing is out of order, last: %s, requested: %d", last, historyID)
}
- h, err := readHistory(freezer, historyID)
+ h, err := readStateHistory(freezer, historyID)
if err != nil {
return err
}
@@ -271,7 +271,7 @@ func unindexSingle(historyID uint64, db ethdb.KeyValueStore, freezer ethdb.Ancie
}
return fmt.Errorf("history unindexing is out of order, last: %s, requested: %d", last, historyID)
}
- h, err := readHistory(freezer, historyID)
+ h, err := readStateHistory(freezer, historyID)
if err != nil {
return err
}
@@ -524,7 +524,7 @@ func (i *indexIniter) index(done chan struct{}, interrupt *atomic.Int32, lastID
if count > historyReadBatch {
count = historyReadBatch
}
- histories, err := readHistories(i.freezer, current, count)
+ histories, err := readStateHistories(i.freezer, current, count)
if err != nil {
// The history read might fall if the history is truncated from
// head due to revert operation.
diff --git a/triedb/pathdb/history_indexer_test.go b/triedb/pathdb/history_indexer_test.go
index abfcafc945..96c87ccb1b 100644
--- a/triedb/pathdb/history_indexer_test.go
+++ b/triedb/pathdb/history_indexer_test.go
@@ -32,7 +32,7 @@ func TestHistoryIndexerShortenDeadlock(t *testing.T) {
freezer, _ := rawdb.NewStateFreezer(t.TempDir(), false, false)
defer freezer.Close()
- histories := makeHistories(100)
+ histories := makeStateHistories(100)
for i, h := range histories {
accountData, storageData, accountIndex, storageIndex := h.encode()
rawdb.WriteStateHistory(freezer, uint64(i+1), h.meta.encode(), accountIndex, storageIndex, accountData, storageData)
diff --git a/triedb/pathdb/history_inspect.go b/triedb/pathdb/history_inspect.go
index 9458e2478b..9b4eea27b4 100644
--- a/triedb/pathdb/history_inspect.go
+++ b/triedb/pathdb/history_inspect.go
@@ -61,7 +61,7 @@ func sanitizeRange(start, end uint64, freezer ethdb.AncientReader) (uint64, uint
return first, last, nil
}
-func inspectHistory(freezer ethdb.AncientReader, start, end uint64, onHistory func(*history, *HistoryStats)) (*HistoryStats, error) {
+func inspectHistory(freezer ethdb.AncientReader, start, end uint64, onHistory func(*stateHistory, *HistoryStats)) (*HistoryStats, error) {
var (
stats = &HistoryStats{}
init = time.Now()
@@ -74,7 +74,7 @@ func inspectHistory(freezer ethdb.AncientReader, start, end uint64, onHistory fu
for id := start; id <= end; id += 1 {
// The entire history object is decoded, although it's unnecessary for
// account inspection. TODO(rjl493456442) optimization is worthwhile.
- h, err := readHistory(freezer, id)
+ h, err := readStateHistory(freezer, id)
if err != nil {
return nil, err
}
@@ -98,7 +98,7 @@ func inspectHistory(freezer ethdb.AncientReader, start, end uint64, onHistory fu
// accountHistory inspects the account history within the range.
func accountHistory(freezer ethdb.AncientReader, address common.Address, start, end uint64) (*HistoryStats, error) {
- return inspectHistory(freezer, start, end, func(h *history, stats *HistoryStats) {
+ return inspectHistory(freezer, start, end, func(h *stateHistory, stats *HistoryStats) {
blob, exists := h.accounts[address]
if !exists {
return
@@ -111,7 +111,7 @@ func accountHistory(freezer ethdb.AncientReader, address common.Address, start,
// storageHistory inspects the storage history within the range.
func storageHistory(freezer ethdb.AncientReader, address common.Address, slot common.Hash, start uint64, end uint64) (*HistoryStats, error) {
slotHash := crypto.Keccak256Hash(slot.Bytes())
- return inspectHistory(freezer, start, end, func(h *history, stats *HistoryStats) {
+ return inspectHistory(freezer, start, end, func(h *stateHistory, stats *HistoryStats) {
slots, exists := h.storages[address]
if !exists {
return
@@ -145,11 +145,11 @@ func historyRange(freezer ethdb.AncientReader) (uint64, uint64, error) {
}
last := head - 1
- fh, err := readHistory(freezer, first)
+ fh, err := readStateHistory(freezer, first)
if err != nil {
return 0, 0, err
}
- lh, err := readHistory(freezer, last)
+ lh, err := readStateHistory(freezer, last)
if err != nil {
return 0, 0, err
}
diff --git a/triedb/pathdb/history_reader_test.go b/triedb/pathdb/history_reader_test.go
index 4eb93fb9c9..e271b271a9 100644
--- a/triedb/pathdb/history_reader_test.go
+++ b/triedb/pathdb/history_reader_test.go
@@ -133,7 +133,7 @@ func testHistoryReader(t *testing.T, historyLimit uint64) {
var (
roots = env.roots
dRoot = env.db.tree.bottom().rootHash()
- hr = newHistoryReader(env.db.diskdb, env.db.freezer)
+ hr = newHistoryReader(env.db.diskdb, env.db.stateFreezer)
)
for _, root := range roots {
if root == dRoot {
diff --git a/triedb/pathdb/history.go b/triedb/pathdb/history_state.go
similarity index 93%
rename from triedb/pathdb/history.go
rename to triedb/pathdb/history_state.go
index 47f224170d..ab8e97b6c0 100644
--- a/triedb/pathdb/history.go
+++ b/triedb/pathdb/history_state.go
@@ -234,12 +234,13 @@ func (m *meta) decode(blob []byte) error {
}
}
-// history represents a set of state changes belong to a block along with
+// stateHistory represents a set of state changes belong to a block along with
// the metadata including the state roots involved in the state transition.
+//
// State history objects in disk are linked with each other by a unique id
// (8-bytes integer), the oldest state history object can be pruned on demand
// in order to control the storage size.
-type history struct {
+type stateHistory struct {
meta *meta // Meta data of history
accounts map[common.Address][]byte // Account data keyed by its address hash
accountList []common.Address // Sorted account hash list
@@ -247,8 +248,8 @@ type history struct {
storageList map[common.Address][]common.Hash // Sorted slot hash list
}
-// newHistory constructs the state history object with provided state change set.
-func newHistory(root common.Hash, parent common.Hash, block uint64, accounts map[common.Address][]byte, storages map[common.Address]map[common.Hash][]byte, rawStorageKey bool) *history {
+// newStateHistory constructs the state history object with provided states.
+func newStateHistory(root common.Hash, parent common.Hash, block uint64, accounts map[common.Address][]byte, storages map[common.Address]map[common.Hash][]byte, rawStorageKey bool) *stateHistory {
var (
accountList = slices.SortedFunc(maps.Keys(accounts), common.Address.Cmp)
storageList = make(map[common.Address][]common.Hash)
@@ -260,7 +261,7 @@ func newHistory(root common.Hash, parent common.Hash, block uint64, accounts map
if !rawStorageKey {
version = stateHistoryV0
}
- return &history{
+ return &stateHistory{
meta: &meta{
version: version,
parent: parent,
@@ -276,7 +277,7 @@ func newHistory(root common.Hash, parent common.Hash, block uint64, accounts map
// stateSet returns the state set, keyed by the hash of the account address
// and the hash of the storage slot key.
-func (h *history) stateSet() (map[common.Hash][]byte, map[common.Hash]map[common.Hash][]byte) {
+func (h *stateHistory) stateSet() (map[common.Hash][]byte, map[common.Hash]map[common.Hash][]byte) {
var (
accounts = make(map[common.Hash][]byte)
storages = make(map[common.Hash]map[common.Hash][]byte)
@@ -304,7 +305,7 @@ func (h *history) stateSet() (map[common.Hash][]byte, map[common.Hash]map[common
// encode serializes the state history and returns four byte streams represent
// concatenated account/storage data, account/storage indexes respectively.
-func (h *history) encode() ([]byte, []byte, []byte, []byte) {
+func (h *stateHistory) encode() ([]byte, []byte, []byte, []byte) {
var (
slotNumber uint32 // the number of processed slots
accountData []byte // the buffer for concatenated account data
@@ -459,7 +460,7 @@ func (r *decoder) readStorage(accIndex accountIndex) ([]common.Hash, map[common.
}
// decode deserializes the account and storage data from the provided byte stream.
-func (h *history) decode(accountData, storageData, accountIndexes, storageIndexes []byte) error {
+func (h *stateHistory) decode(accountData, storageData, accountIndexes, storageIndexes []byte) error {
var (
count = len(accountIndexes) / accountIndexSize
accounts = make(map[common.Address][]byte, count)
@@ -503,8 +504,8 @@ func (h *history) decode(accountData, storageData, accountIndexes, storageIndexe
return nil
}
-// readHistory reads and decodes the state history object by the given id.
-func readHistory(reader ethdb.AncientReader, id uint64) (*history, error) {
+// readStateHistory reads a single state history records with the specified id.
+func readStateHistory(reader ethdb.AncientReader, id uint64) (*stateHistory, error) {
mData, accountIndexes, storageIndexes, accountData, storageData, err := rawdb.ReadStateHistory(reader, id)
if err != nil {
return nil, err
@@ -513,17 +514,16 @@ func readHistory(reader ethdb.AncientReader, id uint64) (*history, error) {
if err := m.decode(mData); err != nil {
return nil, err
}
- h := history{meta: &m}
+ h := stateHistory{meta: &m}
if err := h.decode(accountData, storageData, accountIndexes, storageIndexes); err != nil {
return nil, err
}
return &h, nil
}
-// readHistories reads and decodes a list of state histories with the specific
-// history range.
-func readHistories(freezer ethdb.AncientReader, start uint64, count uint64) ([]*history, error) {
- var histories []*history
+// readStateHistories reads a list of state history records within the specified range.
+func readStateHistories(freezer ethdb.AncientReader, start uint64, count uint64) ([]*stateHistory, error) {
+ var histories []*stateHistory
metaList, aIndexList, sIndexList, aDataList, sDataList, err := rawdb.ReadStateHistoryList(freezer, start, count)
if err != nil {
return nil, err
@@ -533,7 +533,7 @@ func readHistories(freezer ethdb.AncientReader, start uint64, count uint64) ([]*
if err := m.decode(metaList[i]); err != nil {
return nil, err
}
- h := history{meta: &m}
+ h := stateHistory{meta: &m}
if err := h.decode(aDataList[i], sDataList[i], aIndexList[i], sIndexList[i]); err != nil {
return nil, err
}
@@ -542,15 +542,15 @@ func readHistories(freezer ethdb.AncientReader, start uint64, count uint64) ([]*
return histories, nil
}
-// writeHistory persists the state history with the provided state set.
-func writeHistory(writer ethdb.AncientWriter, dl *diffLayer) error {
+// writeStateHistory persists the state history associated with the given diff layer.
+func writeStateHistory(writer ethdb.AncientWriter, dl *diffLayer) error {
// Short circuit if state set is not available.
if dl.states == nil {
return errors.New("state change set is not available")
}
var (
start = time.Now()
- history = newHistory(dl.rootHash(), dl.parentLayer().rootHash(), dl.block, dl.states.accountOrigin, dl.states.storageOrigin, dl.states.rawStorageKey)
+ history = newStateHistory(dl.rootHash(), dl.parentLayer().rootHash(), dl.block, dl.states.accountOrigin, dl.states.storageOrigin, dl.states.rawStorageKey)
)
accountData, storageData, accountIndex, storageIndex := history.encode()
dataSize := common.StorageSize(len(accountData) + len(storageData))
@@ -568,9 +568,9 @@ func writeHistory(writer ethdb.AncientWriter, dl *diffLayer) error {
return nil
}
-// checkHistories retrieves a batch of meta objects with the specified range
+// checkStateHistories retrieves a batch of meta objects with the specified range
// and performs the callback on each item.
-func checkHistories(reader ethdb.AncientReader, start, count uint64, check func(*meta) error) error {
+func checkStateHistories(reader ethdb.AncientReader, start, count uint64, check func(*meta) error) error {
for count > 0 {
number := count
if number > 10000 {
diff --git a/triedb/pathdb/history_test.go b/triedb/pathdb/history_state_test.go
similarity index 89%
rename from triedb/pathdb/history_test.go
rename to triedb/pathdb/history_state_test.go
index 2928d19d74..e154811367 100644
--- a/triedb/pathdb/history_test.go
+++ b/triedb/pathdb/history_state_test.go
@@ -49,36 +49,36 @@ func randomStateSet(n int) (map[common.Address][]byte, map[common.Address]map[co
return accounts, storages
}
-func makeHistory(rawStorageKey bool) *history {
+func makeStateHistory(rawStorageKey bool) *stateHistory {
accounts, storages := randomStateSet(3)
- return newHistory(testrand.Hash(), types.EmptyRootHash, 0, accounts, storages, rawStorageKey)
+ return newStateHistory(testrand.Hash(), types.EmptyRootHash, 0, accounts, storages, rawStorageKey)
}
-func makeHistories(n int) []*history {
+func makeStateHistories(n int) []*stateHistory {
var (
parent = types.EmptyRootHash
- result []*history
+ result []*stateHistory
)
for i := 0; i < n; i++ {
root := testrand.Hash()
accounts, storages := randomStateSet(3)
- h := newHistory(root, parent, uint64(i), accounts, storages, false)
+ h := newStateHistory(root, parent, uint64(i), accounts, storages, false)
parent = root
result = append(result, h)
}
return result
}
-func TestEncodeDecodeHistory(t *testing.T) {
- testEncodeDecodeHistory(t, false)
- testEncodeDecodeHistory(t, true)
+func TestEncodeDecodeStateHistory(t *testing.T) {
+ testEncodeDecodeStateHistory(t, false)
+ testEncodeDecodeStateHistory(t, true)
}
-func testEncodeDecodeHistory(t *testing.T, rawStorageKey bool) {
+func testEncodeDecodeStateHistory(t *testing.T, rawStorageKey bool) {
var (
m meta
- dec history
- obj = makeHistory(rawStorageKey)
+ dec stateHistory
+ obj = makeStateHistory(rawStorageKey)
)
// check if meta data can be correctly encode/decode
blob := obj.meta.encode()
@@ -108,7 +108,7 @@ func testEncodeDecodeHistory(t *testing.T, rawStorageKey bool) {
}
}
-func checkHistory(t *testing.T, db ethdb.KeyValueReader, freezer ethdb.AncientReader, id uint64, root common.Hash, exist bool) {
+func checkStateHistory(t *testing.T, db ethdb.KeyValueReader, freezer ethdb.AncientReader, id uint64, root common.Hash, exist bool) {
blob := rawdb.ReadStateHistoryMeta(freezer, id)
if exist && len(blob) == 0 {
t.Fatalf("Failed to load trie history, %d", id)
@@ -126,14 +126,14 @@ func checkHistory(t *testing.T, db ethdb.KeyValueReader, freezer ethdb.AncientRe
func checkHistoriesInRange(t *testing.T, db ethdb.KeyValueReader, freezer ethdb.AncientReader, from, to uint64, roots []common.Hash, exist bool) {
for i, j := from, 0; i <= to; i, j = i+1, j+1 {
- checkHistory(t, db, freezer, i, roots[j], exist)
+ checkStateHistory(t, db, freezer, i, roots[j], exist)
}
}
-func TestTruncateHeadHistory(t *testing.T) {
+func TestTruncateHeadStateHistory(t *testing.T) {
var (
roots []common.Hash
- hs = makeHistories(10)
+ hs = makeStateHistories(10)
db = rawdb.NewMemoryDatabase()
freezer, _ = rawdb.NewStateFreezer(t.TempDir(), false, false)
)
@@ -158,10 +158,10 @@ func TestTruncateHeadHistory(t *testing.T) {
}
}
-func TestTruncateTailHistory(t *testing.T) {
+func TestTruncateTailStateHistory(t *testing.T) {
var (
roots []common.Hash
- hs = makeHistories(10)
+ hs = makeStateHistories(10)
db = rawdb.NewMemoryDatabase()
freezer, _ = rawdb.NewStateFreezer(t.TempDir(), false, false)
)
@@ -183,7 +183,7 @@ func TestTruncateTailHistory(t *testing.T) {
}
}
-func TestTruncateTailHistories(t *testing.T) {
+func TestTruncateTailStateHistories(t *testing.T) {
var cases = []struct {
limit uint64
expPruned int
@@ -204,7 +204,7 @@ func TestTruncateTailHistories(t *testing.T) {
for i, c := range cases {
var (
roots []common.Hash
- hs = makeHistories(10)
+ hs = makeStateHistories(10)
db = rawdb.NewMemoryDatabase()
freezer, _ = rawdb.NewStateFreezer(t.TempDir()+fmt.Sprintf("%d", i), false, false)
)
@@ -232,7 +232,7 @@ func TestTruncateTailHistories(t *testing.T) {
func TestTruncateOutOfRange(t *testing.T) {
var (
- hs = makeHistories(10)
+ hs = makeStateHistories(10)
db = rawdb.NewMemoryDatabase()
freezer, _ = rawdb.NewStateFreezer(t.TempDir(), false, false)
)
diff --git a/triedb/pathdb/reader.go b/triedb/pathdb/reader.go
index b7b18f13f9..43d12a1678 100644
--- a/triedb/pathdb/reader.go
+++ b/triedb/pathdb/reader.go
@@ -207,11 +207,11 @@ type HistoricalStateReader struct {
// HistoricReader constructs a reader for accessing the requested historic state.
func (db *Database) HistoricReader(root common.Hash) (*HistoricalStateReader, error) {
// Bail out if the state history hasn't been fully indexed
- if db.indexer == nil || !db.indexer.inited() {
- return nil, errors.New("state histories haven't been fully indexed yet")
+ if db.stateIndexer == nil || db.stateFreezer == nil {
+ return nil, fmt.Errorf("historical state %x is not available", root)
}
- if db.freezer == nil {
- return nil, errors.New("state histories are not available")
+ if !db.stateIndexer.inited() {
+ return nil, errors.New("state histories haven't been fully indexed yet")
}
// States at the current disk layer or above are directly accessible via
// db.StateReader.
@@ -230,7 +230,7 @@ func (db *Database) HistoricReader(root common.Hash) (*HistoricalStateReader, er
return &HistoricalStateReader{
id: *id,
db: db,
- reader: newHistoryReader(db.diskdb, db.freezer),
+ reader: newHistoryReader(db.diskdb, db.stateFreezer),
}, nil
}