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/filtermaps/chain_view.go b/core/filtermaps/chain_view.go index 7c48048ad9..35c5ed22a5 100644 --- a/core/filtermaps/chain_view.go +++ b/core/filtermaps/chain_view.go @@ -124,19 +124,12 @@ func (cv *ChainView) RawReceipts(number uint64) types.Receipts { // SharedRange returns the block range shared by two chain views. func (cv *ChainView) SharedRange(cv2 *ChainView) common.Range[uint64] { - cv.lock.Lock() - defer cv.lock.Unlock() - - if cv == nil || cv2 == nil || !cv.extendNonCanonical() || !cv2.extendNonCanonical() { + if cv == nil || cv2 == nil { return common.Range[uint64]{} } - var sharedLen uint64 - for n := min(cv.headNumber+1-uint64(len(cv.hashes)), cv2.headNumber+1-uint64(len(cv2.hashes))); n <= cv.headNumber && n <= cv2.headNumber; n++ { - h1, h2 := cv.blockHash(n), cv2.blockHash(n) - if h1 != h2 || h1 == (common.Hash{}) { - break - } - sharedLen = n + 1 + sharedLen := min(cv.headNumber, cv2.headNumber) + 1 + for sharedLen > 0 && cv.BlockId(sharedLen-1) != cv2.BlockId(sharedLen-1) { + sharedLen-- } return common.NewRange(0, sharedLen) } 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/gasestimator/gasestimator.go b/eth/gasestimator/gasestimator.go index 7e9d8125de..6e79fbd62b 100644 --- a/eth/gasestimator/gasestimator.go +++ b/eth/gasestimator/gasestimator.go @@ -62,6 +62,23 @@ func Estimate(ctx context.Context, call *core.Message, opts *Options, gasCap uin if call.GasLimit >= params.TxGas { hi = call.GasLimit } + + // Cap the maximum gas allowance according to EIP-7825 if the estimation targets Osaka + if hi > params.MaxTxGas { + blockNumber, blockTime := opts.Header.Number, opts.Header.Time + if opts.BlockOverrides != nil { + if opts.BlockOverrides.Number != nil { + blockNumber = opts.BlockOverrides.Number.ToInt() + } + if opts.BlockOverrides.Time != nil { + blockTime = uint64(*opts.BlockOverrides.Time) + } + } + if opts.Config.IsOsaka(blockNumber, blockTime) { + hi = params.MaxTxGas + } + } + // Normalize the max fee per gas the call is willing to spend. var feeCap *big.Int if call.GasFeeCap != nil { @@ -209,6 +226,9 @@ func execute(ctx context.Context, call *core.Message, opts *Options, gasLimit ui if errors.Is(err, core.ErrIntrinsicGas) { return true, nil, nil // Special case, raise gas limit } + if errors.Is(err, core.ErrGasLimitTooHigh) { + return true, nil, nil // Special case, lower gas limit + } return true, nil, err // Bail out } return result.Failed(), result, nil diff --git a/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/sync_test.go b/eth/sync_test.go index cad3a4732e..dc295f2790 100644 --- a/eth/sync_test.go +++ b/eth/sync_test.go @@ -88,9 +88,17 @@ func testSnapSyncDisabling(t *testing.T, ethVer uint, snapVer uint) { if err := empty.handler.downloader.BeaconSync(ethconfig.SnapSync, full.chain.CurrentBlock(), nil); err != nil { t.Fatal("sync failed:", err) } - time.Sleep(time.Second * 5) // Downloader internally has to wait a timer (3s) to be expired before exiting - - if empty.handler.snapSync.Load() { - t.Fatalf("snap sync not disabled after successful synchronisation") + // Downloader internally has to wait for a timer (3s) to be expired before + // exiting. Poll after to determine if sync is disabled. + time.Sleep(time.Second * 3) + for timeout := time.After(time.Second); ; { + select { + case <-timeout: + t.Fatalf("snap sync not disabled after successful synchronisation") + case <-time.After(100 * time.Millisecond): + if !empty.handler.snapSync.Load() { + return + } + } } } 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/supply_test.go b/eth/tracers/internal/tracetest/supply_test.go index 8aedc9d564..2b5a8212aa 100644 --- a/eth/tracers/internal/tracetest/supply_test.go +++ b/eth/tracers/internal/tracetest/supply_test.go @@ -77,7 +77,7 @@ func TestSupplyOmittedFields(t *testing.T) { out, _, err := testSupplyTracer(t, gspec, func(b *core.BlockGen) { b.SetPoS() - }) + }, 1) if err != nil { t.Fatalf("failed to test supply tracer: %v", err) } @@ -120,7 +120,7 @@ func TestSupplyGenesisAlloc(t *testing.T) { ParentHash: common.HexToHash("0x0000000000000000000000000000000000000000000000000000000000000000"), } - out, _, err := testSupplyTracer(t, gspec, emptyBlockGenerationFunc) + out, _, err := testSupplyTracer(t, gspec, emptyBlockGenerationFunc, 1) if err != nil { t.Fatalf("failed to test supply tracer: %v", err) } @@ -148,7 +148,55 @@ func TestSupplyRewards(t *testing.T) { ParentHash: common.HexToHash("0xadeda0a83e337b6c073e3f0e9a17531a04009b397a9588c093b628f21b8bc5a3"), } - out, _, err := testSupplyTracer(t, gspec, emptyBlockGenerationFunc) + out, _, err := testSupplyTracer(t, gspec, emptyBlockGenerationFunc, 1) + if err != nil { + t.Fatalf("failed to test supply tracer: %v", err) + } + + actual := out[expected.Number] + + compareAsJSON(t, expected, actual) +} + +func TestSupplyRewardsWithUncle(t *testing.T) { + var ( + config = *params.AllEthashProtocolChanges + + gspec = &core.Genesis{ + Config: &config, + } + ) + + // Base reward for the miner + baseReward := ethash.ConstantinopleBlockReward.ToBig() + // Miner reward for uncle inclusion is 1/32 of the base reward + uncleInclusionReward := new(big.Int).Rsh(baseReward, 5) + // Uncle miner reward for an uncle that is 1 block behind is 7/8 of the base reward + uncleReward := big.NewInt(7) + uncleReward.Mul(uncleReward, baseReward).Rsh(uncleReward, 3) + + totalReward := baseReward.Add(baseReward, uncleInclusionReward).Add(baseReward, uncleReward) + + expected := supplyInfo{ + Issuance: &supplyInfoIssuance{ + Reward: (*hexutil.Big)(totalReward), + }, + Number: 3, + Hash: common.HexToHash("0x0737d31f8671c18d32b5143833cfa600e4264df62324c9de569668c6de9eed6d"), + ParentHash: common.HexToHash("0x45af6557df87719cb3c7e6f8a98b61508ea74a797733191aececb4c2ec802447"), + } + + // Generate a new chain where block 3 includes an uncle + uncleGenerationFunc := func(b *core.BlockGen) { + if b.Number().Uint64() == 3 { + prevBlock := b.PrevBlock(1) // Block 2 + uncle := types.CopyHeader(prevBlock.Header()) + uncle.Extra = []byte("uncle!") + b.AddUncle(uncle) + } + } + + out, _, err := testSupplyTracer(t, gspec, uncleGenerationFunc, 3) if err != nil { t.Fatalf("failed to test supply tracer: %v", err) } @@ -195,7 +243,7 @@ func TestSupplyEip1559Burn(t *testing.T) { b.AddTx(tx) } - out, chain, err := testSupplyTracer(t, gspec, eip1559BlockGenerationFunc) + out, chain, err := testSupplyTracer(t, gspec, eip1559BlockGenerationFunc, 1) if err != nil { t.Fatalf("failed to test supply tracer: %v", err) } @@ -238,7 +286,7 @@ func TestSupplyWithdrawals(t *testing.T) { }) } - out, chain, err := testSupplyTracer(t, gspec, withdrawalsBlockGenerationFunc) + out, chain, err := testSupplyTracer(t, gspec, withdrawalsBlockGenerationFunc, 1) if err != nil { t.Fatalf("failed to test supply tracer: %v", err) } @@ -318,7 +366,7 @@ func TestSupplySelfdestruct(t *testing.T) { } // 1. Test pre Cancun - preCancunOutput, preCancunChain, err := testSupplyTracer(t, gspec, testBlockGenerationFunc) + preCancunOutput, preCancunChain, err := testSupplyTracer(t, gspec, testBlockGenerationFunc, 1) if err != nil { t.Fatalf("Pre-cancun failed to test supply tracer: %v", err) } @@ -360,7 +408,7 @@ func TestSupplySelfdestruct(t *testing.T) { gspec.Config.CancunTime = &cancunTime gspec.Config.BlobScheduleConfig = params.DefaultBlobSchedule - postCancunOutput, postCancunChain, err := testSupplyTracer(t, gspec, testBlockGenerationFunc) + postCancunOutput, postCancunChain, err := testSupplyTracer(t, gspec, testBlockGenerationFunc, 1) if err != nil { t.Fatalf("Post-cancun failed to test supply tracer: %v", err) } @@ -500,7 +548,7 @@ func TestSupplySelfdestructItselfAndRevert(t *testing.T) { b.AddTx(tx) } - output, chain, err := testSupplyTracer(t, gspec, testBlockGenerationFunc) + output, chain, err := testSupplyTracer(t, gspec, testBlockGenerationFunc, 1) if err != nil { t.Fatalf("failed to test supply tracer: %v", err) } @@ -542,7 +590,7 @@ func TestSupplySelfdestructItselfAndRevert(t *testing.T) { compareAsJSON(t, expected, actual) } -func testSupplyTracer(t *testing.T, genesis *core.Genesis, gen func(*core.BlockGen)) ([]supplyInfo, *core.BlockChain, error) { +func testSupplyTracer(t *testing.T, genesis *core.Genesis, gen func(b *core.BlockGen), numBlocks int) ([]supplyInfo, *core.BlockChain, error) { engine := beacon.New(ethash.NewFaker()) traceOutputPath := filepath.ToSlash(t.TempDir()) @@ -562,7 +610,7 @@ func testSupplyTracer(t *testing.T, genesis *core.Genesis, gen func(*core.BlockG } defer chain.Stop() - _, blocks, _ := core.GenerateChainWithGenesis(genesis, engine, 1, func(i int, b *core.BlockGen) { + _, blocks, _ := core.GenerateChainWithGenesis(genesis, engine, numBlocks, func(i int, b *core.BlockGen) { b.SetCoinbase(common.Address{1}) gen(b) }) 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 b798c06f16..a95a95afe4 100644 --- a/eth/tracers/internal/tracetest/testdata/prestate_tracer/7702_delegate.json +++ b/eth/tracers/internal/tracetest/testdata/prestate_tracer/7702_delegate.json @@ -19,11 +19,13 @@ "0x17816e9a858b161c3e37016d139cf618056cacd4": { "balance": "0x0", "code": "0xef0100b684710e6d5914ad6e64493de2a3c424cc43e970", + "codeHash": "0xca4cab497827c53a640924e1f7ebb69c3280f8ce8cef2d1d2f9a3707def2a856", "nonce": 15809 }, "0x236501327e701692a281934230af0b6be8df3353": { "balance": "0x0", "code": "0x6080604052600a600c565b005b60186014601a565b605e565b565b600060597f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc5473ffffffffffffffffffffffffffffffffffffffff1690565b905090565b3660008037600080366000845af43d6000803e808015607c573d6000f35b3d6000fdfea26469706673582212200b737106e31d6abde738d261a4c4f12fcdfac5141ebc6ab5ffe4cf6e1630aaed64736f6c63430008140033", + "codeHash": "0x297bbcbd2b9ae035f750536c62603b5b7240c69b04fe22eec21cf6fcbb61179f", "nonce": 1, "storage": { "0x078d9cc432fb3eab476f678ef9a73d8ca570f23897c68eb99b2721ebf46e5a9e": "0x0000000000000000000000000000000000000000000000000000000000000000", @@ -42,21 +44,25 @@ "0xb684710e6d5914ad6e64493de2a3c424cc43e970": { "balance": "0x0", "code": "0x60806040525f4711156100b6575f3273ffffffffffffffffffffffffffffffffffffffff16476040516100319061048b565b5f6040518083038185875af1925050503d805f811461006b576040519150601f19603f3d011682016040523d82523d5f602084013e610070565b606091505b50509050806100b4576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016100ab906104f9565b60405180910390fd5b505b73ffffffffffffffffffffffffffffffffffffffff80166001336100da9190610563565b73ffffffffffffffffffffffffffffffffffffffff161115610131576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610128906105f4565b60405180910390fd5b73b9df4a9ba45917e71d664d51462d46926e4798e873ffffffffffffffffffffffffffffffffffffffff166001336101699190610563565b73ffffffffffffffffffffffffffffffffffffffff160361045c575f8036906101929190610631565b5f1c90505f73cda6461f1a30c618373f5790a83e1569fb685cba73ffffffffffffffffffffffffffffffffffffffff16631f3a71ba306040518263ffffffff1660e01b81526004016101e491906106af565b602060405180830381865afa1580156101ff573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061022391906106ff565b90508181106104595773cda6461f1a30c618373f5790a83e1569fb685cba73ffffffffffffffffffffffffffffffffffffffff1663a9059cbb5f836040518363ffffffff1660e01b815260040161027b929190610739565b6020604051808303815f875af1158015610297573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906102bb9190610795565b6102fa576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016102f1906104f9565b60405180910390fd5b5f73236501327e701692a281934230af0b6be8df335373ffffffffffffffffffffffffffffffffffffffff166370a08231306040518263ffffffff1660e01b815260040161034891906106af565b602060405180830381865afa158015610363573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061038791906106ff565b905073236501327e701692a281934230af0b6be8df335373ffffffffffffffffffffffffffffffffffffffff1663a9059cbb32836040518363ffffffff1660e01b81526004016103d8929190610739565b6020604051808303815f875af11580156103f4573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906104189190610795565b610457576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161044e9061080a565b60405180910390fd5b505b50505b005b5f81905092915050565b50565b5f6104765f8361045e565b915061048182610468565b5f82019050919050565b5f6104958261046b565b9150819050919050565b5f82825260208201905092915050565b7f5472616e73666572206661696c656400000000000000000000000000000000005f82015250565b5f6104e3600f8361049f565b91506104ee826104af565b602082019050919050565b5f6020820190508181035f830152610510816104d7565b9050919050565b5f73ffffffffffffffffffffffffffffffffffffffff82169050919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b5f61056d82610517565b915061057883610517565b9250828201905073ffffffffffffffffffffffffffffffffffffffff8111156105a4576105a3610536565b5b92915050565b7f50616e69632831372900000000000000000000000000000000000000000000005f82015250565b5f6105de60098361049f565b91506105e9826105aa565b602082019050919050565b5f6020820190508181035f83015261060b816105d2565b9050919050565b5f82905092915050565b5f819050919050565b5f82821b905092915050565b5f61063c8383610612565b82610647813561061c565b92506020821015610687576106827fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff83602003600802610625565b831692505b505092915050565b5f61069982610517565b9050919050565b6106a98161068f565b82525050565b5f6020820190506106c25f8301846106a0565b92915050565b5f80fd5b5f819050919050565b6106de816106cc565b81146106e8575f80fd5b50565b5f815190506106f9816106d5565b92915050565b5f60208284031215610714576107136106c8565b5b5f610721848285016106eb565b91505092915050565b610733816106cc565b82525050565b5f60408201905061074c5f8301856106a0565b610759602083018461072a565b9392505050565b5f8115159050919050565b61077481610760565b811461077e575f80fd5b50565b5f8151905061078f8161076b565b92915050565b5f602082840312156107aa576107a96106c8565b5b5f6107b784828501610781565b91505092915050565b7f546f6b656e207472616e73666572206661696c656400000000000000000000005f82015250565b5f6107f460158361049f565b91506107ff826107c0565b602082019050919050565b5f6020820190508181035f830152610821816107e8565b905091905056fea2646970667358221220b6a06cc7b930dc4e34352a145f3548d57ec5a60d0097c1979ef363376bf9a69164736f6c63430008140033", + "codeHash": "0x1c83a51aa39aa075951b4fa0aa146c33a33e035e0d7023b9de7f27a5a3d15058", "nonce": 1 }, "0xb9df4a9ba45917e71d664d51462d46926e4798e7": { "balance": "0x597af049b190a724", "code": "0xef0100000000009b1d0af20d8c6d0a44e162d11f9b8f00", + "codeHash": "0xbb1a21a37f4391e14c4817bca5df4ed60b84e372053b367731ccd8ab0fb6daf1", "nonce": 1887 }, "0xbdb50eff425fb2b1b67fea21b8420eeb6d99ccc0": { "balance": "0x0", "code": "0x6080604052600436106101cd5760003560e01c80637ecebe00116100f7578063a9059cbb11610095578063d505accf11610064578063d505accf146105b2578063dd62ed3e146105d2578063f1127ed814610637578063f2fde38b1461068357600080fd5b8063a9059cbb14610509578063ad3cb1cc14610529578063b119490e14610572578063c3cda5201461059257600080fd5b80638e539e8c116100d15780638e539e8c1461048857806391ddadf4146104a857806395d89b41146104d45780639ab24eb0146104e957600080fd5b80637ecebe001461040357806384b0196e146104235780638da5cb5b1461044b57600080fd5b80634bf5d7e91161016f5780635c19a95c1161013e5780635c19a95c146103795780636fcfff451461039957806370a08231146103ce578063715018a6146103ee57600080fd5b80634bf5d7e9146102dc5780634f1ef286146102f157806352d1902d14610306578063587cde1e1461031b57600080fd5b806323b872dd116101ab57806323b872dd1461026b578063313ce5671461028b5780633644e515146102a75780633a46b1a8146102bc57600080fd5b806306fdde03146101d2578063095ea7b3146101fd57806318160ddd1461022d575b600080fd5b3480156101de57600080fd5b506101e76106a3565b6040516101f49190612a81565b60405180910390f35b34801561020957600080fd5b5061021d610218366004612ab0565b61075e565b60405190151581526020016101f4565b34801561023957600080fd5b507f52c63247e1f47db19d5ce0460030c497f067ca4cebf71ba98eeadabe20bace02545b6040519081526020016101f4565b34801561027757600080fd5b5061021d610286366004612ada565b610778565b34801561029757600080fd5b50604051601281526020016101f4565b3480156102b357600080fd5b5061025d61079e565b3480156102c857600080fd5b5061025d6102d7366004612ab0565b6107ad565b3480156102e857600080fd5b506101e7610845565b6103046102ff366004612ba2565b6108d6565b005b34801561031257600080fd5b5061025d6108f5565b34801561032757600080fd5b50610361610336366004612c04565b6001600160a01b03908116600090815260008051602061312283398151915260205260409020541690565b6040516001600160a01b0390911681526020016101f4565b34801561038557600080fd5b50610304610394366004612c04565b610924565b3480156103a557600080fd5b506103b96103b4366004612c04565b61092f565b60405163ffffffff90911681526020016101f4565b3480156103da57600080fd5b5061025d6103e9366004612c04565b61093a565b3480156103fa57600080fd5b5061030461097f565b34801561040f57600080fd5b5061025d61041e366004612c04565b610993565b34801561042f57600080fd5b5061043861099e565b6040516101f49796959493929190612c1f565b34801561045757600080fd5b507f9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c199300546001600160a01b0316610361565b34801561049457600080fd5b5061025d6104a3366004612cd1565b610a9a565b3480156104b457600080fd5b506104bd610b16565b60405165ffffffffffff90911681526020016101f4565b3480156104e057600080fd5b506101e7610b20565b3480156104f557600080fd5b5061025d610504366004612c04565b610b71565b34801561051557600080fd5b5061021d610524366004612ab0565b610bd1565b34801561053557600080fd5b506101e76040518060400160405280600581526020017f352e302e3000000000000000000000000000000000000000000000000000000081525081565b34801561057e57600080fd5b5061030461058d366004612d0a565b610bdf565b34801561059e57600080fd5b506103046105ad366004612d88565b610d4b565b3480156105be57600080fd5b506103046105cd366004612de0565b610e21565b3480156105de57600080fd5b5061025d6105ed366004612e4a565b6001600160a01b0391821660009081527f52c63247e1f47db19d5ce0460030c497f067ca4cebf71ba98eeadabe20bace016020908152604080832093909416825291909152205490565b34801561064357600080fd5b50610657610652366004612e7d565b610fac565b60408051825165ffffffffffff1681526020928301516001600160d01b031692810192909252016101f4565b34801561068f57600080fd5b5061030461069e366004612c04565b610fca565b606060007f52c63247e1f47db19d5ce0460030c497f067ca4cebf71ba98eeadabe20bace005b90508060030180546106da90612ebd565b80601f016020809104026020016040519081016040528092919081815260200182805461070690612ebd565b80156107535780601f1061072857610100808354040283529160200191610753565b820191906000526020600020905b81548152906001019060200180831161073657829003601f168201915b505050505091505090565b60003361076c818585611021565b60019150505b92915050565b600033610786858285611033565b6107918585856110e9565b60019150505b9392505050565b60006107a8611161565b905090565b6000600080516020613122833981519152816107c7610b16565b90508065ffffffffffff16841061080757604051637669fc0f60e11b81526004810185905265ffffffffffff821660248201526044015b60405180910390fd5b6108336108138561116b565b6001600160a01b03871660009081526001850160205260409020906111a2565b6001600160d01b031695945050505050565b606061084f61125b565b65ffffffffffff1661085f610b16565b65ffffffffffff161461089e576040517f6ff0714000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5060408051808201909152601d81527f6d6f64653d626c6f636b6e756d6265722666726f6d3d64656661756c74000000602082015290565b6108de611266565b6108e78261131d565b6108f18282611325565b5050565b60006108ff61140d565b507f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc90565b336108f18183611456565b600061077282611513565b6000807f52c63247e1f47db19d5ce0460030c497f067ca4cebf71ba98eeadabe20bace005b6001600160a01b0390931660009081526020939093525050604090205490565b610987611564565b61099160006115d8565b565b600061077282611656565b600060608082808083817fa16a46d94261c7517cc8ff89f61c0ce93598e3c849801011dee649a6a557d10080549091501580156109dd57506001810154155b610a43576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f4549503731323a20556e696e697469616c697a6564000000000000000000000060448201526064016107fe565b610a4b611661565b610a536116b2565b604080516000808252602082019092527f0f000000000000000000000000000000000000000000000000000000000000009c939b5091995046985030975095509350915050565b600060008051602061312283398151915281610ab4610b16565b90508065ffffffffffff168410610aef57604051637669fc0f60e11b81526004810185905265ffffffffffff821660248201526044016107fe565b610b05610afb8561116b565b60028401906111a2565b6001600160d01b0316949350505050565b60006107a861125b565b7f52c63247e1f47db19d5ce0460030c497f067ca4cebf71ba98eeadabe20bace0480546060917f52c63247e1f47db19d5ce0460030c497f067ca4cebf71ba98eeadabe20bace00916106da90612ebd565b6001600160a01b03811660009081527fe8b26c30fad74198956032a3533d903385d56dd795af560196f9c78d4af40d016020526040812060008051602061312283398151915290610bc1906116dc565b6001600160d01b03169392505050565b60003361076c8185856110e9565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00805468010000000000000000810460ff16159067ffffffffffffffff16600081158015610c2a5750825b905060008267ffffffffffffffff166001148015610c475750303b155b905081158015610c55575080155b15610c8c576040517ff92ee8a900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b845467ffffffffffffffff191660011785558315610cc057845468ff00000000000000001916680100000000000000001785555b610cca8888611718565b610cd38861172a565b610cdb611771565b610ce433611779565b610cec611771565b610cf6338761178a565b8315610d4157845468ff000000000000000019168555604051600181527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d29060200160405180910390a15b5050505050505050565b83421115610d88576040517f4683af0e000000000000000000000000000000000000000000000000000000008152600481018590526024016107fe565b604080517fe48329057bfd03d55e49b547132e39cffd9c1820ad7b9d4c5307691425d15adf60208201526001600160a01b038816918101919091526060810186905260808101859052600090610e0290610dfa9060a001604051602081830303815290604052805190602001206117c0565b858585611808565b9050610e0e8187611836565b610e188188611456565b50505050505050565b83421115610e5e576040517f62791302000000000000000000000000000000000000000000000000000000008152600481018590526024016107fe565b60007f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c9888888610eca8c6001600160a01b031660009081527f5ab42ced628888259c08ac98db1eb0cf702fc1501344311d8b100cd1bfe4bb006020526040902080546001810190915590565b6040805160208101969096526001600160a01b0394851690860152929091166060840152608083015260a082015260c0810186905260e0016040516020818303038152906040528051906020012090506000610f25826117c0565b90506000610f3582878787611808565b9050896001600160a01b0316816001600160a01b031614610f95576040517f4b800e460000000000000000000000000000000000000000000000000000000081526001600160a01b0380831660048301528b1660248201526044016107fe565b610fa08a8a8a611021565b50505050505050505050565b604080518082019091526000808252602082015261079783836118c1565b610fd2611564565b6001600160a01b038116611015576040517f1e4fbdf7000000000000000000000000000000000000000000000000000000008152600060048201526024016107fe565b61101e816115d8565b50565b61102e838383600161192c565b505050565b6001600160a01b0383811660009081527f52c63247e1f47db19d5ce0460030c497f067ca4cebf71ba98eeadabe20bace01602090815260408083209386168352929052205460001981146110e357818110156110d4576040517ffb8f41b20000000000000000000000000000000000000000000000000000000081526001600160a01b038416600482015260248101829052604481018390526064016107fe565b6110e38484848403600061192c565b50505050565b6001600160a01b03831661112c576040517f96c6fd1e000000000000000000000000000000000000000000000000000000008152600060048201526024016107fe565b6001600160a01b0382166111565760405163ec442f0560e01b8152600060048201526024016107fe565b61102e838383611a58565b60006107a8611a63565b600065ffffffffffff82111561119e576040516306dfcc6560e41b815260306004820152602481018390526044016107fe565b5090565b8154600090818160058111156112015760006111bd84611ad7565b6111c79085612f0d565b60008881526020902090915081015465ffffffffffff90811690871610156111f1578091506111ff565b6111fc816001612f20565b92505b505b600061120f87878585611bbf565b9050801561124d5761123487611226600184612f0d565b600091825260209091200190565b54660100000000000090046001600160d01b0316611250565b60005b979650505050505050565b60006107a84361116b565b306001600160a01b037f000000000000000000000000bdb50eff425fb2b1b67fea21b8420eeb6d99ccc01614806112ff57507f000000000000000000000000bdb50eff425fb2b1b67fea21b8420eeb6d99ccc06001600160a01b03166112f37f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc546001600160a01b031690565b6001600160a01b031614155b156109915760405163703e46dd60e11b815260040160405180910390fd5b61101e611564565b816001600160a01b03166352d1902d6040518163ffffffff1660e01b8152600401602060405180830381865afa92505050801561137f575060408051601f3d908101601f1916820190925261137c91810190612f33565b60015b6113a757604051634c9c8ce360e01b81526001600160a01b03831660048201526024016107fe565b7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc8114611403576040517faa1d49a4000000000000000000000000000000000000000000000000000000008152600481018290526024016107fe565b61102e8383611c21565b306001600160a01b037f000000000000000000000000bdb50eff425fb2b1b67fea21b8420eeb6d99ccc016146109915760405163703e46dd60e11b815260040160405180910390fd5b6000805160206131228339815191526000611496846001600160a01b03908116600090815260008051602061312283398151915260205260409020541690565b6001600160a01b03858116600081815260208690526040808220805473ffffffffffffffffffffffffffffffffffffffff1916898616908117909155905194955093928516927f3134e8a2e6d97e929a7e54011ea5485d7d196dd5f0ba4d4ef95803e8e3fc257f9190a46110e3818461150e87611c77565b611c82565b6001600160a01b03811660009081527fe8b26c30fad74198956032a3533d903385d56dd795af560196f9c78d4af40d0160205260408120546000805160206131228339815191529061079790611dfc565b336115967f9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c199300546001600160a01b031690565b6001600160a01b031614610991576040517f118cdaa70000000000000000000000000000000000000000000000000000000081523360048201526024016107fe565b7f9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c199300805473ffffffffffffffffffffffffffffffffffffffff1981166001600160a01b03848116918217845560405192169182907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a3505050565b600061077282611e2d565b7fa16a46d94261c7517cc8ff89f61c0ce93598e3c849801011dee649a6a557d10280546060917fa16a46d94261c7517cc8ff89f61c0ce93598e3c849801011dee649a6a557d100916106da90612ebd565b606060007fa16a46d94261c7517cc8ff89f61c0ce93598e3c849801011dee649a6a557d1006106c9565b8054600090801561170f576116f683611226600184612f0d565b54660100000000000090046001600160d01b0316610797565b60009392505050565b611720611e56565b6108f18282611ebd565b611732611e56565b61101e816040518060400160405280600181526020017f3100000000000000000000000000000000000000000000000000000000000000815250611f20565b610991611e56565b611781611e56565b61101e81611f93565b6001600160a01b0382166117b45760405163ec442f0560e01b8152600060048201526024016107fe565b6108f160008383611a58565b60006107726117cd611161565b836040517f19010000000000000000000000000000000000000000000000000000000000008152600281019290925260228201526042902090565b60008060008061181a88888888611f9b565b92509250925061182a828261206a565b50909695505050505050565b6001600160a01b03821660009081527f5ab42ced628888259c08ac98db1eb0cf702fc1501344311d8b100cd1bfe4bb006020526040902080546001810190915581811461102e576040517f752d88c00000000000000000000000000000000000000000000000000000000081526001600160a01b0384166004820152602481018290526044016107fe565b604080518082018252600080825260208083018290526001600160a01b03861682527fe8b26c30fad74198956032a3533d903385d56dd795af560196f9c78d4af40d0190529190912060008051602061312283398151915290611924908461216e565b949350505050565b7f52c63247e1f47db19d5ce0460030c497f067ca4cebf71ba98eeadabe20bace006001600160a01b038516611990576040517fe602df05000000000000000000000000000000000000000000000000000000008152600060048201526024016107fe565b6001600160a01b0384166119d3576040517f94280d62000000000000000000000000000000000000000000000000000000008152600060048201526024016107fe565b6001600160a01b03808616600090815260018301602090815260408083209388168352929052208390558115611a5157836001600160a01b0316856001600160a01b03167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92585604051611a4891815260200190565b60405180910390a35b5050505050565b61102e8383836121e1565b60007f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f611a8e612280565b611a966122fc565b60408051602081019490945283019190915260608201524660808201523060a082015260c00160405160208183030381529060405280519060200120905090565b600081600003611ae957506000919050565b60006001611af684612352565b901c6001901b90506001818481611b0f57611b0f612f4c565b048201901c90506001818481611b2757611b27612f4c565b048201901c90506001818481611b3f57611b3f612f4c565b048201901c90506001818481611b5757611b57612f4c565b048201901c90506001818481611b6f57611b6f612f4c565b048201901c90506001818481611b8757611b87612f4c565b048201901c90506001818481611b9f57611b9f612f4c565b048201901c905061079781828581611bb957611bb9612f4c565b046123e6565b60005b81831015611c19576000611bd684846123fc565b60008781526020902090915065ffffffffffff86169082015465ffffffffffff161115611c0557809250611c13565b611c10816001612f20565b93505b50611bc2565b509392505050565b611c2a82612417565b6040516001600160a01b038316907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b90600090a2805115611c6f5761102e828261249b565b6108f1612511565b60006107728261093a565b6000805160206131228339815191526001600160a01b0384811690841614801590611cad5750600082115b156110e3576001600160a01b03841615611d57576001600160a01b038416600090815260018201602052604081208190611cf290612549611ced87612555565b612589565b6001600160d01b031691506001600160d01b03169150856001600160a01b03167fdec2bacdd2f05b59de34da9b523dff8be42e5e38e818c82fdb0bae774387a7248383604051611d4c929190918252602082015260400190565b60405180910390a250505b6001600160a01b038316156110e3576001600160a01b038316600090815260018201602052604081208190611d92906125c2611ced87612555565b6001600160d01b031691506001600160d01b03169150846001600160a01b03167fdec2bacdd2f05b59de34da9b523dff8be42e5e38e818c82fdb0bae774387a7248383604051611dec929190918252602082015260400190565b60405180910390a2505050505050565b600063ffffffff82111561119e576040516306dfcc6560e41b815260206004820152602481018390526044016107fe565b6000807f5ab42ced628888259c08ac98db1eb0cf702fc1501344311d8b100cd1bfe4bb0061095f565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a005468010000000000000000900460ff16610991576040517fd7e6bcf800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611ec5611e56565b7f52c63247e1f47db19d5ce0460030c497f067ca4cebf71ba98eeadabe20bace007f52c63247e1f47db19d5ce0460030c497f067ca4cebf71ba98eeadabe20bace03611f118482612fb0565b50600481016110e38382612fb0565b611f28611e56565b7fa16a46d94261c7517cc8ff89f61c0ce93598e3c849801011dee649a6a557d1007fa16a46d94261c7517cc8ff89f61c0ce93598e3c849801011dee649a6a557d102611f748482612fb0565b5060038101611f838382612fb0565b5060008082556001909101555050565b610fd2611e56565b600080807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a0841115611fd65750600091506003905082612060565b604080516000808252602082018084528a905260ff891692820192909252606081018790526080810186905260019060a0016020604051602081039080840390855afa15801561202a573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b03811661205657506000925060019150829050612060565b9250600091508190505b9450945094915050565b600082600381111561207e5761207e613070565b03612087575050565b600182600381111561209b5761209b613070565b036120d2576040517ff645eedf00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60028260038111156120e6576120e6613070565b03612120576040517ffce698f7000000000000000000000000000000000000000000000000000000008152600481018290526024016107fe565b600382600381111561213457612134613070565b036108f1576040517fd78bce0c000000000000000000000000000000000000000000000000000000008152600481018290526024016107fe565b6040805180820190915260008082526020820152826000018263ffffffff168154811061219d5761219d613086565b60009182526020918290206040805180820190915291015465ffffffffffff81168252660100000000000090046001600160d01b0316918101919091529392505050565b6121ec8383836125ce565b6001600160a01b0383166122755760006122247f52c63247e1f47db19d5ce0460030c497f067ca4cebf71ba98eeadabe20bace025490565b90506001600160d01b0380821115612272576040517f1cb15d2600000000000000000000000000000000000000000000000000000000815260048101839052602481018290526044016107fe565b50505b61102e838383612737565b60007fa16a46d94261c7517cc8ff89f61c0ce93598e3c849801011dee649a6a557d100816122ac611661565b8051909150156122c457805160209091012092915050565b815480156122d3579392505050565b7fc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470935050505090565b60007fa16a46d94261c7517cc8ff89f61c0ce93598e3c849801011dee649a6a557d100816123286116b2565b80519091501561234057805160209091012092915050565b600182015480156122d3579392505050565b600080608083901c1561236757608092831c92015b604083901c1561237957604092831c92015b602083901c1561238b57602092831c92015b601083901c1561239d57601092831c92015b600883901c156123af57600892831c92015b600483901c156123c157600492831c92015b600283901c156123d357600292831c92015b600183901c156107725760010192915050565b60008183106123f55781610797565b5090919050565b600061240b600284841861309c565b61079790848416612f20565b806001600160a01b03163b60000361244d57604051634c9c8ce360e01b81526001600160a01b03821660048201526024016107fe565b7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc805473ffffffffffffffffffffffffffffffffffffffff19166001600160a01b0392909216919091179055565b6060600080846001600160a01b0316846040516124b891906130be565b600060405180830381855af49150503d80600081146124f3576040519150601f19603f3d011682016040523d82523d6000602084013e6124f8565b606091505b50915091506125088583836127cd565b95945050505050565b3415610991576040517fb398979f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600061079782846130da565b60006001600160d01b0382111561119e576040516306dfcc6560e41b815260d06004820152602481018390526044016107fe565b6000806125b5612597610b16565b6125ad6125a3886116dc565b868863ffffffff16565b879190612842565b915091505b935093915050565b60006107978284613101565b7f52c63247e1f47db19d5ce0460030c497f067ca4cebf71ba98eeadabe20bace006001600160a01b03841661261c57818160020160008282546126119190612f20565b909155506126a79050565b6001600160a01b03841660009081526020829052604090205482811015612688576040517fe450d38c0000000000000000000000000000000000000000000000000000000081526001600160a01b038616600482015260248101829052604481018490526064016107fe565b6001600160a01b03851660009081526020839052604090209083900390555b6001600160a01b0383166126c55760028101805483900390556126e4565b6001600160a01b03831660009081526020829052604090208054830190555b826001600160a01b0316846001600160a01b03167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8460405161272991815260200190565b60405180910390a350505050565b6000805160206131228339815191526001600160a01b03841661276a57612767816002016125c2611ced85612555565b50505b6001600160a01b03831661278e5761278b81600201612549611ced85612555565b50505b6001600160a01b03848116600090815260008051602061312283398151915260205260408082205486841683529120546110e392918216911684611c82565b6060826127e2576127dd82612850565b610797565b81511580156127f957506001600160a01b0384163b155b1561283b576040517f9996b3150000000000000000000000000000000000000000000000000000000081526001600160a01b03851660048201526024016107fe565b5080610797565b6000806125b5858585612892565b8051156128605780518082602001fd5b6040517f1425ea4200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8254600090819080156129d35760006128b087611226600185612f0d565b60408051808201909152905465ffffffffffff80821680845266010000000000009092046001600160d01b031660208401529192509087161015612920576040517f2520601d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b805165ffffffffffff80881691160361296f578461294388611226600186612f0d565b80546001600160d01b039290921666010000000000000265ffffffffffff9092169190911790556129c3565b6040805180820190915265ffffffffffff80881682526001600160d01b0380881660208085019182528b54600181018d5560008d815291909120945191519092166601000000000000029216919091179101555b6020015192508391506125ba9050565b50506040805180820190915265ffffffffffff80851682526001600160d01b0380851660208085019182528854600181018a5560008a81529182209551925190931666010000000000000291909316179201919091559050816125ba565b60005b83811015612a4c578181015183820152602001612a34565b50506000910152565b60008151808452612a6d816020860160208601612a31565b601f01601f19169290920160200192915050565b6020815260006107976020830184612a55565b80356001600160a01b0381168114612aab57600080fd5b919050565b60008060408385031215612ac357600080fd5b612acc83612a94565b946020939093013593505050565b600080600060608486031215612aef57600080fd5b612af884612a94565b9250612b0660208501612a94565b9150604084013590509250925092565b634e487b7160e01b600052604160045260246000fd5b600067ffffffffffffffff80841115612b4757612b47612b16565b604051601f8501601f19908116603f01168101908282118183101715612b6f57612b6f612b16565b81604052809350858152868686011115612b8857600080fd5b858560208301376000602087830101525050509392505050565b60008060408385031215612bb557600080fd5b612bbe83612a94565b9150602083013567ffffffffffffffff811115612bda57600080fd5b8301601f81018513612beb57600080fd5b612bfa85823560208401612b2c565b9150509250929050565b600060208284031215612c1657600080fd5b61079782612a94565b7fff00000000000000000000000000000000000000000000000000000000000000881681526000602060e081840152612c5b60e084018a612a55565b8381036040850152612c6d818a612a55565b606085018990526001600160a01b038816608086015260a0850187905284810360c0860152855180825283870192509083019060005b81811015612cbf57835183529284019291840191600101612ca3565b50909c9b505050505050505050505050565b600060208284031215612ce357600080fd5b5035919050565b600082601f830112612cfb57600080fd5b61079783833560208501612b2c565b600080600060608486031215612d1f57600080fd5b833567ffffffffffffffff80821115612d3757600080fd5b612d4387838801612cea565b94506020860135915080821115612d5957600080fd5b50612d6686828701612cea565b925050604084013590509250925092565b803560ff81168114612aab57600080fd5b60008060008060008060c08789031215612da157600080fd5b612daa87612a94565b95506020870135945060408701359350612dc660608801612d77565b92506080870135915060a087013590509295509295509295565b600080600080600080600060e0888a031215612dfb57600080fd5b612e0488612a94565b9650612e1260208901612a94565b95506040880135945060608801359350612e2e60808901612d77565b925060a0880135915060c0880135905092959891949750929550565b60008060408385031215612e5d57600080fd5b612e6683612a94565b9150612e7460208401612a94565b90509250929050565b60008060408385031215612e9057600080fd5b612e9983612a94565b9150602083013563ffffffff81168114612eb257600080fd5b809150509250929050565b600181811c90821680612ed157607f821691505b602082108103612ef157634e487b7160e01b600052602260045260246000fd5b50919050565b634e487b7160e01b600052601160045260246000fd5b8181038181111561077257610772612ef7565b8082018082111561077257610772612ef7565b600060208284031215612f4557600080fd5b5051919050565b634e487b7160e01b600052601260045260246000fd5b601f82111561102e57600081815260208120601f850160051c81016020861015612f895750805b601f850160051c820191505b81811015612fa857828155600101612f95565b505050505050565b815167ffffffffffffffff811115612fca57612fca612b16565b612fde81612fd88454612ebd565b84612f62565b602080601f8311600181146130135760008415612ffb5750858301515b600019600386901b1c1916600185901b178555612fa8565b600085815260208120601f198616915b8281101561304257888601518255948401946001909101908401613023565b50858210156130605787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b634e487b7160e01b600052602160045260246000fd5b634e487b7160e01b600052603260045260246000fd5b6000826130b957634e487b7160e01b600052601260045260246000fd5b500490565b600082516130d0818460208701612a31565b9190910192915050565b6001600160d01b038281168282160390808211156130fa576130fa612ef7565b5092915050565b6001600160d01b038181168382160190808211156130fa576130fa612ef756fee8b26c30fad74198956032a3533d903385d56dd795af560196f9c78d4af40d00a2646970667358221220c2a4c7c504a36ab9781f5fb312d81d27f781047ab9f97621c7f031a185ecb78864736f6c63430008140033", + "codeHash": "0x1c83a51aa39aa075951b4fa0aa146c33a33e035e0d7023b9de7f27a5a3d15058", "nonce": 1 }, "0xcda6461f1a30c618373f5790a83e1569fb685cba": { "balance": "0x0", "code": "0x608060405234801561001057600080fd5b50600436106100ea5760003560e01c8063313ce5671161008c578063a9059cbb11610066578063a9059cbb146102ab578063dd62ed3e146102be578063e6fd48bc146102d4578063fc0c546a146102fb57600080fd5b8063313ce567146101f857806370a082311461023157806395d89b411461025157600080fd5b80631514617e116100c85780631514617e146101a857806318160ddd146101cf5780631f3a71ba146101d757806323b872dd146101ea57600080fd5b80630483a7f6146100ef57806306fdde0314610122578063095ea7b314610185575b600080fd5b61010f6100fd366004610926565b60006020819052908152604090205481565b6040519081526020015b60405180910390f35b604080517f466c75656e636520546f6b656e20284c6f636b65642900000000000000000000602082015281519082019091527f000000000000000000000000000000000000000000000000000000000000001681525b6040516101199190610965565b610198610193366004610998565b61033a565b6040519015158152602001610119565b61010f7f0000000000000000000000000000000000000000000000000000000001e1338081565b60025461010f565b61010f6101e5366004610926565b61038a565b6101986101933660046109c2565b61021f7f000000000000000000000000000000000000000000000000000000000000001281565b60405160ff9091168152602001610119565b61010f61023f366004610926565b60016020526000908152604090205481565b604080517f464c542d4c000000000000000000000000000000000000000000000000000000602082015281519082019091527f00000000000000000000000000000000000000000000000000000000000000058152610178565b6101986102b9366004610998565b610485565b61010f6102cc3660046109fe565b600092915050565b61010f7f0000000000000000000000000000000000000000000000000000000067afabe881565b6103227f000000000000000000000000236501327e701692a281934230af0b6be8df335381565b6040516001600160a01b039091168152602001610119565b60405162461bcd60e51b815260206004820152601560248201527f556e737570706f72746564206f7065726174696f6e000000000000000000000060448201526000906064015b60405180910390fd5b60007f0000000000000000000000000000000000000000000000000000000067afabe842116103bb57506000919050565b6001600160a01b0382166000908152602081815260408083205460019092528220547f0000000000000000000000000000000000000000000000000000000001e13380929061040a9083610a47565b905060006104387f0000000000000000000000000000000000000000000000000000000067afabe842610a47565b905060008482106104545761044d8385610a47565b905061047b565b60006104608686610a5a565b90508361046d8285610a7c565b6104779190610a47565b9150505b9695505050505050565b60006001600160a01b038316156105045760405162461bcd60e51b815260206004820152602960248201527f5472616e7366657220616c6c6f776564206f6e6c7920746f20746865207a657260448201527f6f206164647265737300000000000000000000000000000000000000000000006064820152608401610381565b3361050f8184610568565b836001600160a01b0316816001600160a01b03167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8560405161055491815260200190565b60405180910390a360019150505b92915050565b60006105738361038a565b9050600081116105c55760405162461bcd60e51b815260206004820152601d60248201527f4e6f7420656e6f756768207468652072656c6561736520616d6f756e740000006044820152606401610381565b8115610620578082111561061b5760405162461bcd60e51b815260206004820152601d60248201527f4e6f7420656e6f756768207468652072656c6561736520616d6f756e740000006044820152606401610381565b610624565b8091505b6001600160a01b0383166000908152600160205260408120805484929061064c908490610a47565b9250508190555081600260008282546106659190610a47565b9091555061069f90506001600160a01b037f000000000000000000000000236501327e701692a281934230af0b6be8df33531684846106a4565b505050565b604080516001600160a01b03848116602483015260448083018590528351808403909101815260649092019092526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fa9059cbb0000000000000000000000000000000000000000000000000000000017905261069f9185919060009061073090841683610797565b905080516000141580156107555750808060200190518101906107539190610a93565b155b1561069f576040517f5274afe70000000000000000000000000000000000000000000000000000000081526001600160a01b0384166004820152602401610381565b60606107a5838360006107ac565b9392505050565b6060814710156107ea576040517fcd786059000000000000000000000000000000000000000000000000000000008152306004820152602401610381565b600080856001600160a01b031684866040516108069190610ab5565b60006040518083038185875af1925050503d8060008114610843576040519150601f19603f3d011682016040523d82523d6000602084013e610848565b606091505b509150915061047b86838360608261086857610863826108c8565b6107a5565b815115801561087f57506001600160a01b0384163b155b156108c1576040517f9996b3150000000000000000000000000000000000000000000000000000000081526001600160a01b0385166004820152602401610381565b50806107a5565b8051156108d85780518082602001fd5b6040517f1425ea4200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80356001600160a01b038116811461092157600080fd5b919050565b60006020828403121561093857600080fd5b6107a58261090a565b60005b8381101561095c578181015183820152602001610944565b50506000910152565b6020815260008251806020840152610984816040850160208701610941565b601f01601f19169190910160400192915050565b600080604083850312156109ab57600080fd5b6109b48361090a565b946020939093013593505050565b6000806000606084860312156109d757600080fd5b6109e08461090a565b92506109ee6020850161090a565b9150604084013590509250925092565b60008060408385031215610a1157600080fd5b610a1a8361090a565b9150610a286020840161090a565b90509250929050565b634e487b7160e01b600052601160045260246000fd5b8181038181111561056257610562610a31565b600082610a7757634e487b7160e01b600052601260045260246000fd5b500490565b808202811582820484141761056257610562610a31565b600060208284031215610aa557600080fd5b815180151581146107a557600080fd5b60008251610ac7818460208701610941565b919091019291505056fea2646970667358221220aa9a251bde32306273cb5f6045040ac4b74b767bd02205c60c6003c5346ac34c64736f6c63430008140033", + "codeHash": "0xc10e7caa80b2af0d4faa10cd68f5a88dc5bbcf9d4f056677c3d259c8f31040e9", "nonce": 1, "storage": { "0x0000000000000000000000000000000000000000000000000000000000000002": "0x0000000000000000000000000000000000000000007b74591c97f086c1057bee", @@ -112,11 +118,13 @@ "0x17816e9a858b161c3e37016d139cf618056cacd4": { "balance": "0x0", "code": "0xef0100b684710e6d5914ad6e64493de2a3c424cc43e970", + "codeHash":"0xca4cab497827c53a640924e1f7ebb69c3280f8ce8cef2d1d2f9a3707def2a856", "nonce": 15809 }, "0x236501327e701692a281934230af0b6be8df3353": { "balance": "0x0", "code": "0x6080604052600a600c565b005b60186014601a565b605e565b565b600060597f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc5473ffffffffffffffffffffffffffffffffffffffff1690565b905090565b3660008037600080366000845af43d6000803e808015607c573d6000f35b3d6000fdfea26469706673582212200b737106e31d6abde738d261a4c4f12fcdfac5141ebc6ab5ffe4cf6e1630aaed64736f6c63430008140033", + "codeHash": "0x297bbcbd2b9ae035f750536c62603b5b7240c69b04fe22eec21cf6fcbb61179f", "nonce": 1, "storage": { "0x078d9cc432fb3eab476f678ef9a73d8ca570f23897c68eb99b2721ebf46e5a9e": "0x0000000000000000000000000000000000000000000000000000000000000000", @@ -135,21 +143,25 @@ "0xb684710e6d5914ad6e64493de2a3c424cc43e970": { "balance": "0x0", "code": "0x60806040525f4711156100b6575f3273ffffffffffffffffffffffffffffffffffffffff16476040516100319061048b565b5f6040518083038185875af1925050503d805f811461006b576040519150601f19603f3d011682016040523d82523d5f602084013e610070565b606091505b50509050806100b4576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016100ab906104f9565b60405180910390fd5b505b73ffffffffffffffffffffffffffffffffffffffff80166001336100da9190610563565b73ffffffffffffffffffffffffffffffffffffffff161115610131576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610128906105f4565b60405180910390fd5b73b9df4a9ba45917e71d664d51462d46926e4798e873ffffffffffffffffffffffffffffffffffffffff166001336101699190610563565b73ffffffffffffffffffffffffffffffffffffffff160361045c575f8036906101929190610631565b5f1c90505f73cda6461f1a30c618373f5790a83e1569fb685cba73ffffffffffffffffffffffffffffffffffffffff16631f3a71ba306040518263ffffffff1660e01b81526004016101e491906106af565b602060405180830381865afa1580156101ff573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061022391906106ff565b90508181106104595773cda6461f1a30c618373f5790a83e1569fb685cba73ffffffffffffffffffffffffffffffffffffffff1663a9059cbb5f836040518363ffffffff1660e01b815260040161027b929190610739565b6020604051808303815f875af1158015610297573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906102bb9190610795565b6102fa576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016102f1906104f9565b60405180910390fd5b5f73236501327e701692a281934230af0b6be8df335373ffffffffffffffffffffffffffffffffffffffff166370a08231306040518263ffffffff1660e01b815260040161034891906106af565b602060405180830381865afa158015610363573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061038791906106ff565b905073236501327e701692a281934230af0b6be8df335373ffffffffffffffffffffffffffffffffffffffff1663a9059cbb32836040518363ffffffff1660e01b81526004016103d8929190610739565b6020604051808303815f875af11580156103f4573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906104189190610795565b610457576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161044e9061080a565b60405180910390fd5b505b50505b005b5f81905092915050565b50565b5f6104765f8361045e565b915061048182610468565b5f82019050919050565b5f6104958261046b565b9150819050919050565b5f82825260208201905092915050565b7f5472616e73666572206661696c656400000000000000000000000000000000005f82015250565b5f6104e3600f8361049f565b91506104ee826104af565b602082019050919050565b5f6020820190508181035f830152610510816104d7565b9050919050565b5f73ffffffffffffffffffffffffffffffffffffffff82169050919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b5f61056d82610517565b915061057883610517565b9250828201905073ffffffffffffffffffffffffffffffffffffffff8111156105a4576105a3610536565b5b92915050565b7f50616e69632831372900000000000000000000000000000000000000000000005f82015250565b5f6105de60098361049f565b91506105e9826105aa565b602082019050919050565b5f6020820190508181035f83015261060b816105d2565b9050919050565b5f82905092915050565b5f819050919050565b5f82821b905092915050565b5f61063c8383610612565b82610647813561061c565b92506020821015610687576106827fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff83602003600802610625565b831692505b505092915050565b5f61069982610517565b9050919050565b6106a98161068f565b82525050565b5f6020820190506106c25f8301846106a0565b92915050565b5f80fd5b5f819050919050565b6106de816106cc565b81146106e8575f80fd5b50565b5f815190506106f9816106d5565b92915050565b5f60208284031215610714576107136106c8565b5b5f610721848285016106eb565b91505092915050565b610733816106cc565b82525050565b5f60408201905061074c5f8301856106a0565b610759602083018461072a565b9392505050565b5f8115159050919050565b61077481610760565b811461077e575f80fd5b50565b5f8151905061078f8161076b565b92915050565b5f602082840312156107aa576107a96106c8565b5b5f6107b784828501610781565b91505092915050565b7f546f6b656e207472616e73666572206661696c656400000000000000000000005f82015250565b5f6107f460158361049f565b91506107ff826107c0565b602082019050919050565b5f6020820190508181035f830152610821816107e8565b905091905056fea2646970667358221220b6a06cc7b930dc4e34352a145f3548d57ec5a60d0097c1979ef363376bf9a69164736f6c63430008140033", + "codeHash":"0x710e40f71ebfefb907b9970505d085952d073dedc9a67e7ce2db450194c9ad04", "nonce": 1 }, "0xb9df4a9ba45917e71d664d51462d46926e4798e7": { "balance": "0x597af049b190a724", "code": "0xef0100000000009b1d0af20d8c6d0a44e162d11f9b8f00", + "codeHash":"0xbb1a21a37f4391e14c4817bca5df4ed60b84e372053b367731ccd8ab0fb6daf1", "nonce": 1887 }, "0xbdb50eff425fb2b1b67fea21b8420eeb6d99ccc0": { "balance": "0x0", "code": "0x6080604052600436106101cd5760003560e01c80637ecebe00116100f7578063a9059cbb11610095578063d505accf11610064578063d505accf146105b2578063dd62ed3e146105d2578063f1127ed814610637578063f2fde38b1461068357600080fd5b8063a9059cbb14610509578063ad3cb1cc14610529578063b119490e14610572578063c3cda5201461059257600080fd5b80638e539e8c116100d15780638e539e8c1461048857806391ddadf4146104a857806395d89b41146104d45780639ab24eb0146104e957600080fd5b80637ecebe001461040357806384b0196e146104235780638da5cb5b1461044b57600080fd5b80634bf5d7e91161016f5780635c19a95c1161013e5780635c19a95c146103795780636fcfff451461039957806370a08231146103ce578063715018a6146103ee57600080fd5b80634bf5d7e9146102dc5780634f1ef286146102f157806352d1902d14610306578063587cde1e1461031b57600080fd5b806323b872dd116101ab57806323b872dd1461026b578063313ce5671461028b5780633644e515146102a75780633a46b1a8146102bc57600080fd5b806306fdde03146101d2578063095ea7b3146101fd57806318160ddd1461022d575b600080fd5b3480156101de57600080fd5b506101e76106a3565b6040516101f49190612a81565b60405180910390f35b34801561020957600080fd5b5061021d610218366004612ab0565b61075e565b60405190151581526020016101f4565b34801561023957600080fd5b507f52c63247e1f47db19d5ce0460030c497f067ca4cebf71ba98eeadabe20bace02545b6040519081526020016101f4565b34801561027757600080fd5b5061021d610286366004612ada565b610778565b34801561029757600080fd5b50604051601281526020016101f4565b3480156102b357600080fd5b5061025d61079e565b3480156102c857600080fd5b5061025d6102d7366004612ab0565b6107ad565b3480156102e857600080fd5b506101e7610845565b6103046102ff366004612ba2565b6108d6565b005b34801561031257600080fd5b5061025d6108f5565b34801561032757600080fd5b50610361610336366004612c04565b6001600160a01b03908116600090815260008051602061312283398151915260205260409020541690565b6040516001600160a01b0390911681526020016101f4565b34801561038557600080fd5b50610304610394366004612c04565b610924565b3480156103a557600080fd5b506103b96103b4366004612c04565b61092f565b60405163ffffffff90911681526020016101f4565b3480156103da57600080fd5b5061025d6103e9366004612c04565b61093a565b3480156103fa57600080fd5b5061030461097f565b34801561040f57600080fd5b5061025d61041e366004612c04565b610993565b34801561042f57600080fd5b5061043861099e565b6040516101f49796959493929190612c1f565b34801561045757600080fd5b507f9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c199300546001600160a01b0316610361565b34801561049457600080fd5b5061025d6104a3366004612cd1565b610a9a565b3480156104b457600080fd5b506104bd610b16565b60405165ffffffffffff90911681526020016101f4565b3480156104e057600080fd5b506101e7610b20565b3480156104f557600080fd5b5061025d610504366004612c04565b610b71565b34801561051557600080fd5b5061021d610524366004612ab0565b610bd1565b34801561053557600080fd5b506101e76040518060400160405280600581526020017f352e302e3000000000000000000000000000000000000000000000000000000081525081565b34801561057e57600080fd5b5061030461058d366004612d0a565b610bdf565b34801561059e57600080fd5b506103046105ad366004612d88565b610d4b565b3480156105be57600080fd5b506103046105cd366004612de0565b610e21565b3480156105de57600080fd5b5061025d6105ed366004612e4a565b6001600160a01b0391821660009081527f52c63247e1f47db19d5ce0460030c497f067ca4cebf71ba98eeadabe20bace016020908152604080832093909416825291909152205490565b34801561064357600080fd5b50610657610652366004612e7d565b610fac565b60408051825165ffffffffffff1681526020928301516001600160d01b031692810192909252016101f4565b34801561068f57600080fd5b5061030461069e366004612c04565b610fca565b606060007f52c63247e1f47db19d5ce0460030c497f067ca4cebf71ba98eeadabe20bace005b90508060030180546106da90612ebd565b80601f016020809104026020016040519081016040528092919081815260200182805461070690612ebd565b80156107535780601f1061072857610100808354040283529160200191610753565b820191906000526020600020905b81548152906001019060200180831161073657829003601f168201915b505050505091505090565b60003361076c818585611021565b60019150505b92915050565b600033610786858285611033565b6107918585856110e9565b60019150505b9392505050565b60006107a8611161565b905090565b6000600080516020613122833981519152816107c7610b16565b90508065ffffffffffff16841061080757604051637669fc0f60e11b81526004810185905265ffffffffffff821660248201526044015b60405180910390fd5b6108336108138561116b565b6001600160a01b03871660009081526001850160205260409020906111a2565b6001600160d01b031695945050505050565b606061084f61125b565b65ffffffffffff1661085f610b16565b65ffffffffffff161461089e576040517f6ff0714000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5060408051808201909152601d81527f6d6f64653d626c6f636b6e756d6265722666726f6d3d64656661756c74000000602082015290565b6108de611266565b6108e78261131d565b6108f18282611325565b5050565b60006108ff61140d565b507f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc90565b336108f18183611456565b600061077282611513565b6000807f52c63247e1f47db19d5ce0460030c497f067ca4cebf71ba98eeadabe20bace005b6001600160a01b0390931660009081526020939093525050604090205490565b610987611564565b61099160006115d8565b565b600061077282611656565b600060608082808083817fa16a46d94261c7517cc8ff89f61c0ce93598e3c849801011dee649a6a557d10080549091501580156109dd57506001810154155b610a43576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f4549503731323a20556e696e697469616c697a6564000000000000000000000060448201526064016107fe565b610a4b611661565b610a536116b2565b604080516000808252602082019092527f0f000000000000000000000000000000000000000000000000000000000000009c939b5091995046985030975095509350915050565b600060008051602061312283398151915281610ab4610b16565b90508065ffffffffffff168410610aef57604051637669fc0f60e11b81526004810185905265ffffffffffff821660248201526044016107fe565b610b05610afb8561116b565b60028401906111a2565b6001600160d01b0316949350505050565b60006107a861125b565b7f52c63247e1f47db19d5ce0460030c497f067ca4cebf71ba98eeadabe20bace0480546060917f52c63247e1f47db19d5ce0460030c497f067ca4cebf71ba98eeadabe20bace00916106da90612ebd565b6001600160a01b03811660009081527fe8b26c30fad74198956032a3533d903385d56dd795af560196f9c78d4af40d016020526040812060008051602061312283398151915290610bc1906116dc565b6001600160d01b03169392505050565b60003361076c8185856110e9565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00805468010000000000000000810460ff16159067ffffffffffffffff16600081158015610c2a5750825b905060008267ffffffffffffffff166001148015610c475750303b155b905081158015610c55575080155b15610c8c576040517ff92ee8a900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b845467ffffffffffffffff191660011785558315610cc057845468ff00000000000000001916680100000000000000001785555b610cca8888611718565b610cd38861172a565b610cdb611771565b610ce433611779565b610cec611771565b610cf6338761178a565b8315610d4157845468ff000000000000000019168555604051600181527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d29060200160405180910390a15b5050505050505050565b83421115610d88576040517f4683af0e000000000000000000000000000000000000000000000000000000008152600481018590526024016107fe565b604080517fe48329057bfd03d55e49b547132e39cffd9c1820ad7b9d4c5307691425d15adf60208201526001600160a01b038816918101919091526060810186905260808101859052600090610e0290610dfa9060a001604051602081830303815290604052805190602001206117c0565b858585611808565b9050610e0e8187611836565b610e188188611456565b50505050505050565b83421115610e5e576040517f62791302000000000000000000000000000000000000000000000000000000008152600481018590526024016107fe565b60007f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c9888888610eca8c6001600160a01b031660009081527f5ab42ced628888259c08ac98db1eb0cf702fc1501344311d8b100cd1bfe4bb006020526040902080546001810190915590565b6040805160208101969096526001600160a01b0394851690860152929091166060840152608083015260a082015260c0810186905260e0016040516020818303038152906040528051906020012090506000610f25826117c0565b90506000610f3582878787611808565b9050896001600160a01b0316816001600160a01b031614610f95576040517f4b800e460000000000000000000000000000000000000000000000000000000081526001600160a01b0380831660048301528b1660248201526044016107fe565b610fa08a8a8a611021565b50505050505050505050565b604080518082019091526000808252602082015261079783836118c1565b610fd2611564565b6001600160a01b038116611015576040517f1e4fbdf7000000000000000000000000000000000000000000000000000000008152600060048201526024016107fe565b61101e816115d8565b50565b61102e838383600161192c565b505050565b6001600160a01b0383811660009081527f52c63247e1f47db19d5ce0460030c497f067ca4cebf71ba98eeadabe20bace01602090815260408083209386168352929052205460001981146110e357818110156110d4576040517ffb8f41b20000000000000000000000000000000000000000000000000000000081526001600160a01b038416600482015260248101829052604481018390526064016107fe565b6110e38484848403600061192c565b50505050565b6001600160a01b03831661112c576040517f96c6fd1e000000000000000000000000000000000000000000000000000000008152600060048201526024016107fe565b6001600160a01b0382166111565760405163ec442f0560e01b8152600060048201526024016107fe565b61102e838383611a58565b60006107a8611a63565b600065ffffffffffff82111561119e576040516306dfcc6560e41b815260306004820152602481018390526044016107fe565b5090565b8154600090818160058111156112015760006111bd84611ad7565b6111c79085612f0d565b60008881526020902090915081015465ffffffffffff90811690871610156111f1578091506111ff565b6111fc816001612f20565b92505b505b600061120f87878585611bbf565b9050801561124d5761123487611226600184612f0d565b600091825260209091200190565b54660100000000000090046001600160d01b0316611250565b60005b979650505050505050565b60006107a84361116b565b306001600160a01b037f000000000000000000000000bdb50eff425fb2b1b67fea21b8420eeb6d99ccc01614806112ff57507f000000000000000000000000bdb50eff425fb2b1b67fea21b8420eeb6d99ccc06001600160a01b03166112f37f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc546001600160a01b031690565b6001600160a01b031614155b156109915760405163703e46dd60e11b815260040160405180910390fd5b61101e611564565b816001600160a01b03166352d1902d6040518163ffffffff1660e01b8152600401602060405180830381865afa92505050801561137f575060408051601f3d908101601f1916820190925261137c91810190612f33565b60015b6113a757604051634c9c8ce360e01b81526001600160a01b03831660048201526024016107fe565b7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc8114611403576040517faa1d49a4000000000000000000000000000000000000000000000000000000008152600481018290526024016107fe565b61102e8383611c21565b306001600160a01b037f000000000000000000000000bdb50eff425fb2b1b67fea21b8420eeb6d99ccc016146109915760405163703e46dd60e11b815260040160405180910390fd5b6000805160206131228339815191526000611496846001600160a01b03908116600090815260008051602061312283398151915260205260409020541690565b6001600160a01b03858116600081815260208690526040808220805473ffffffffffffffffffffffffffffffffffffffff1916898616908117909155905194955093928516927f3134e8a2e6d97e929a7e54011ea5485d7d196dd5f0ba4d4ef95803e8e3fc257f9190a46110e3818461150e87611c77565b611c82565b6001600160a01b03811660009081527fe8b26c30fad74198956032a3533d903385d56dd795af560196f9c78d4af40d0160205260408120546000805160206131228339815191529061079790611dfc565b336115967f9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c199300546001600160a01b031690565b6001600160a01b031614610991576040517f118cdaa70000000000000000000000000000000000000000000000000000000081523360048201526024016107fe565b7f9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c199300805473ffffffffffffffffffffffffffffffffffffffff1981166001600160a01b03848116918217845560405192169182907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a3505050565b600061077282611e2d565b7fa16a46d94261c7517cc8ff89f61c0ce93598e3c849801011dee649a6a557d10280546060917fa16a46d94261c7517cc8ff89f61c0ce93598e3c849801011dee649a6a557d100916106da90612ebd565b606060007fa16a46d94261c7517cc8ff89f61c0ce93598e3c849801011dee649a6a557d1006106c9565b8054600090801561170f576116f683611226600184612f0d565b54660100000000000090046001600160d01b0316610797565b60009392505050565b611720611e56565b6108f18282611ebd565b611732611e56565b61101e816040518060400160405280600181526020017f3100000000000000000000000000000000000000000000000000000000000000815250611f20565b610991611e56565b611781611e56565b61101e81611f93565b6001600160a01b0382166117b45760405163ec442f0560e01b8152600060048201526024016107fe565b6108f160008383611a58565b60006107726117cd611161565b836040517f19010000000000000000000000000000000000000000000000000000000000008152600281019290925260228201526042902090565b60008060008061181a88888888611f9b565b92509250925061182a828261206a565b50909695505050505050565b6001600160a01b03821660009081527f5ab42ced628888259c08ac98db1eb0cf702fc1501344311d8b100cd1bfe4bb006020526040902080546001810190915581811461102e576040517f752d88c00000000000000000000000000000000000000000000000000000000081526001600160a01b0384166004820152602481018290526044016107fe565b604080518082018252600080825260208083018290526001600160a01b03861682527fe8b26c30fad74198956032a3533d903385d56dd795af560196f9c78d4af40d0190529190912060008051602061312283398151915290611924908461216e565b949350505050565b7f52c63247e1f47db19d5ce0460030c497f067ca4cebf71ba98eeadabe20bace006001600160a01b038516611990576040517fe602df05000000000000000000000000000000000000000000000000000000008152600060048201526024016107fe565b6001600160a01b0384166119d3576040517f94280d62000000000000000000000000000000000000000000000000000000008152600060048201526024016107fe565b6001600160a01b03808616600090815260018301602090815260408083209388168352929052208390558115611a5157836001600160a01b0316856001600160a01b03167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92585604051611a4891815260200190565b60405180910390a35b5050505050565b61102e8383836121e1565b60007f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f611a8e612280565b611a966122fc565b60408051602081019490945283019190915260608201524660808201523060a082015260c00160405160208183030381529060405280519060200120905090565b600081600003611ae957506000919050565b60006001611af684612352565b901c6001901b90506001818481611b0f57611b0f612f4c565b048201901c90506001818481611b2757611b27612f4c565b048201901c90506001818481611b3f57611b3f612f4c565b048201901c90506001818481611b5757611b57612f4c565b048201901c90506001818481611b6f57611b6f612f4c565b048201901c90506001818481611b8757611b87612f4c565b048201901c90506001818481611b9f57611b9f612f4c565b048201901c905061079781828581611bb957611bb9612f4c565b046123e6565b60005b81831015611c19576000611bd684846123fc565b60008781526020902090915065ffffffffffff86169082015465ffffffffffff161115611c0557809250611c13565b611c10816001612f20565b93505b50611bc2565b509392505050565b611c2a82612417565b6040516001600160a01b038316907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b90600090a2805115611c6f5761102e828261249b565b6108f1612511565b60006107728261093a565b6000805160206131228339815191526001600160a01b0384811690841614801590611cad5750600082115b156110e3576001600160a01b03841615611d57576001600160a01b038416600090815260018201602052604081208190611cf290612549611ced87612555565b612589565b6001600160d01b031691506001600160d01b03169150856001600160a01b03167fdec2bacdd2f05b59de34da9b523dff8be42e5e38e818c82fdb0bae774387a7248383604051611d4c929190918252602082015260400190565b60405180910390a250505b6001600160a01b038316156110e3576001600160a01b038316600090815260018201602052604081208190611d92906125c2611ced87612555565b6001600160d01b031691506001600160d01b03169150846001600160a01b03167fdec2bacdd2f05b59de34da9b523dff8be42e5e38e818c82fdb0bae774387a7248383604051611dec929190918252602082015260400190565b60405180910390a2505050505050565b600063ffffffff82111561119e576040516306dfcc6560e41b815260206004820152602481018390526044016107fe565b6000807f5ab42ced628888259c08ac98db1eb0cf702fc1501344311d8b100cd1bfe4bb0061095f565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a005468010000000000000000900460ff16610991576040517fd7e6bcf800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611ec5611e56565b7f52c63247e1f47db19d5ce0460030c497f067ca4cebf71ba98eeadabe20bace007f52c63247e1f47db19d5ce0460030c497f067ca4cebf71ba98eeadabe20bace03611f118482612fb0565b50600481016110e38382612fb0565b611f28611e56565b7fa16a46d94261c7517cc8ff89f61c0ce93598e3c849801011dee649a6a557d1007fa16a46d94261c7517cc8ff89f61c0ce93598e3c849801011dee649a6a557d102611f748482612fb0565b5060038101611f838382612fb0565b5060008082556001909101555050565b610fd2611e56565b600080807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a0841115611fd65750600091506003905082612060565b604080516000808252602082018084528a905260ff891692820192909252606081018790526080810186905260019060a0016020604051602081039080840390855afa15801561202a573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b03811661205657506000925060019150829050612060565b9250600091508190505b9450945094915050565b600082600381111561207e5761207e613070565b03612087575050565b600182600381111561209b5761209b613070565b036120d2576040517ff645eedf00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60028260038111156120e6576120e6613070565b03612120576040517ffce698f7000000000000000000000000000000000000000000000000000000008152600481018290526024016107fe565b600382600381111561213457612134613070565b036108f1576040517fd78bce0c000000000000000000000000000000000000000000000000000000008152600481018290526024016107fe565b6040805180820190915260008082526020820152826000018263ffffffff168154811061219d5761219d613086565b60009182526020918290206040805180820190915291015465ffffffffffff81168252660100000000000090046001600160d01b0316918101919091529392505050565b6121ec8383836125ce565b6001600160a01b0383166122755760006122247f52c63247e1f47db19d5ce0460030c497f067ca4cebf71ba98eeadabe20bace025490565b90506001600160d01b0380821115612272576040517f1cb15d2600000000000000000000000000000000000000000000000000000000815260048101839052602481018290526044016107fe565b50505b61102e838383612737565b60007fa16a46d94261c7517cc8ff89f61c0ce93598e3c849801011dee649a6a557d100816122ac611661565b8051909150156122c457805160209091012092915050565b815480156122d3579392505050565b7fc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470935050505090565b60007fa16a46d94261c7517cc8ff89f61c0ce93598e3c849801011dee649a6a557d100816123286116b2565b80519091501561234057805160209091012092915050565b600182015480156122d3579392505050565b600080608083901c1561236757608092831c92015b604083901c1561237957604092831c92015b602083901c1561238b57602092831c92015b601083901c1561239d57601092831c92015b600883901c156123af57600892831c92015b600483901c156123c157600492831c92015b600283901c156123d357600292831c92015b600183901c156107725760010192915050565b60008183106123f55781610797565b5090919050565b600061240b600284841861309c565b61079790848416612f20565b806001600160a01b03163b60000361244d57604051634c9c8ce360e01b81526001600160a01b03821660048201526024016107fe565b7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc805473ffffffffffffffffffffffffffffffffffffffff19166001600160a01b0392909216919091179055565b6060600080846001600160a01b0316846040516124b891906130be565b600060405180830381855af49150503d80600081146124f3576040519150601f19603f3d011682016040523d82523d6000602084013e6124f8565b606091505b50915091506125088583836127cd565b95945050505050565b3415610991576040517fb398979f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600061079782846130da565b60006001600160d01b0382111561119e576040516306dfcc6560e41b815260d06004820152602481018390526044016107fe565b6000806125b5612597610b16565b6125ad6125a3886116dc565b868863ffffffff16565b879190612842565b915091505b935093915050565b60006107978284613101565b7f52c63247e1f47db19d5ce0460030c497f067ca4cebf71ba98eeadabe20bace006001600160a01b03841661261c57818160020160008282546126119190612f20565b909155506126a79050565b6001600160a01b03841660009081526020829052604090205482811015612688576040517fe450d38c0000000000000000000000000000000000000000000000000000000081526001600160a01b038616600482015260248101829052604481018490526064016107fe565b6001600160a01b03851660009081526020839052604090209083900390555b6001600160a01b0383166126c55760028101805483900390556126e4565b6001600160a01b03831660009081526020829052604090208054830190555b826001600160a01b0316846001600160a01b03167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8460405161272991815260200190565b60405180910390a350505050565b6000805160206131228339815191526001600160a01b03841661276a57612767816002016125c2611ced85612555565b50505b6001600160a01b03831661278e5761278b81600201612549611ced85612555565b50505b6001600160a01b03848116600090815260008051602061312283398151915260205260408082205486841683529120546110e392918216911684611c82565b6060826127e2576127dd82612850565b610797565b81511580156127f957506001600160a01b0384163b155b1561283b576040517f9996b3150000000000000000000000000000000000000000000000000000000081526001600160a01b03851660048201526024016107fe565b5080610797565b6000806125b5858585612892565b8051156128605780518082602001fd5b6040517f1425ea4200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8254600090819080156129d35760006128b087611226600185612f0d565b60408051808201909152905465ffffffffffff80821680845266010000000000009092046001600160d01b031660208401529192509087161015612920576040517f2520601d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b805165ffffffffffff80881691160361296f578461294388611226600186612f0d565b80546001600160d01b039290921666010000000000000265ffffffffffff9092169190911790556129c3565b6040805180820190915265ffffffffffff80881682526001600160d01b0380881660208085019182528b54600181018d5560008d815291909120945191519092166601000000000000029216919091179101555b6020015192508391506125ba9050565b50506040805180820190915265ffffffffffff80851682526001600160d01b0380851660208085019182528854600181018a5560008a81529182209551925190931666010000000000000291909316179201919091559050816125ba565b60005b83811015612a4c578181015183820152602001612a34565b50506000910152565b60008151808452612a6d816020860160208601612a31565b601f01601f19169290920160200192915050565b6020815260006107976020830184612a55565b80356001600160a01b0381168114612aab57600080fd5b919050565b60008060408385031215612ac357600080fd5b612acc83612a94565b946020939093013593505050565b600080600060608486031215612aef57600080fd5b612af884612a94565b9250612b0660208501612a94565b9150604084013590509250925092565b634e487b7160e01b600052604160045260246000fd5b600067ffffffffffffffff80841115612b4757612b47612b16565b604051601f8501601f19908116603f01168101908282118183101715612b6f57612b6f612b16565b81604052809350858152868686011115612b8857600080fd5b858560208301376000602087830101525050509392505050565b60008060408385031215612bb557600080fd5b612bbe83612a94565b9150602083013567ffffffffffffffff811115612bda57600080fd5b8301601f81018513612beb57600080fd5b612bfa85823560208401612b2c565b9150509250929050565b600060208284031215612c1657600080fd5b61079782612a94565b7fff00000000000000000000000000000000000000000000000000000000000000881681526000602060e081840152612c5b60e084018a612a55565b8381036040850152612c6d818a612a55565b606085018990526001600160a01b038816608086015260a0850187905284810360c0860152855180825283870192509083019060005b81811015612cbf57835183529284019291840191600101612ca3565b50909c9b505050505050505050505050565b600060208284031215612ce357600080fd5b5035919050565b600082601f830112612cfb57600080fd5b61079783833560208501612b2c565b600080600060608486031215612d1f57600080fd5b833567ffffffffffffffff80821115612d3757600080fd5b612d4387838801612cea565b94506020860135915080821115612d5957600080fd5b50612d6686828701612cea565b925050604084013590509250925092565b803560ff81168114612aab57600080fd5b60008060008060008060c08789031215612da157600080fd5b612daa87612a94565b95506020870135945060408701359350612dc660608801612d77565b92506080870135915060a087013590509295509295509295565b600080600080600080600060e0888a031215612dfb57600080fd5b612e0488612a94565b9650612e1260208901612a94565b95506040880135945060608801359350612e2e60808901612d77565b925060a0880135915060c0880135905092959891949750929550565b60008060408385031215612e5d57600080fd5b612e6683612a94565b9150612e7460208401612a94565b90509250929050565b60008060408385031215612e9057600080fd5b612e9983612a94565b9150602083013563ffffffff81168114612eb257600080fd5b809150509250929050565b600181811c90821680612ed157607f821691505b602082108103612ef157634e487b7160e01b600052602260045260246000fd5b50919050565b634e487b7160e01b600052601160045260246000fd5b8181038181111561077257610772612ef7565b8082018082111561077257610772612ef7565b600060208284031215612f4557600080fd5b5051919050565b634e487b7160e01b600052601260045260246000fd5b601f82111561102e57600081815260208120601f850160051c81016020861015612f895750805b601f850160051c820191505b81811015612fa857828155600101612f95565b505050505050565b815167ffffffffffffffff811115612fca57612fca612b16565b612fde81612fd88454612ebd565b84612f62565b602080601f8311600181146130135760008415612ffb5750858301515b600019600386901b1c1916600185901b178555612fa8565b600085815260208120601f198616915b8281101561304257888601518255948401946001909101908401613023565b50858210156130605787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b634e487b7160e01b600052602160045260246000fd5b634e487b7160e01b600052603260045260246000fd5b6000826130b957634e487b7160e01b600052601260045260246000fd5b500490565b600082516130d0818460208701612a31565b9190910192915050565b6001600160d01b038281168282160390808211156130fa576130fa612ef7565b5092915050565b6001600160d01b038181168382160190808211156130fa576130fa612ef756fee8b26c30fad74198956032a3533d903385d56dd795af560196f9c78d4af40d00a2646970667358221220c2a4c7c504a36ab9781f5fb312d81d27f781047ab9f97621c7f031a185ecb78864736f6c63430008140033", + "codeHash": "0x1c83a51aa39aa075951b4fa0aa146c33a33e035e0d7023b9de7f27a5a3d15058", "nonce": 1 }, "0xcda6461f1a30c618373f5790a83e1569fb685cba": { "balance": "0x0", "code": "0x608060405234801561001057600080fd5b50600436106100ea5760003560e01c8063313ce5671161008c578063a9059cbb11610066578063a9059cbb146102ab578063dd62ed3e146102be578063e6fd48bc146102d4578063fc0c546a146102fb57600080fd5b8063313ce567146101f857806370a082311461023157806395d89b411461025157600080fd5b80631514617e116100c85780631514617e146101a857806318160ddd146101cf5780631f3a71ba146101d757806323b872dd146101ea57600080fd5b80630483a7f6146100ef57806306fdde0314610122578063095ea7b314610185575b600080fd5b61010f6100fd366004610926565b60006020819052908152604090205481565b6040519081526020015b60405180910390f35b604080517f466c75656e636520546f6b656e20284c6f636b65642900000000000000000000602082015281519082019091527f000000000000000000000000000000000000000000000000000000000000001681525b6040516101199190610965565b610198610193366004610998565b61033a565b6040519015158152602001610119565b61010f7f0000000000000000000000000000000000000000000000000000000001e1338081565b60025461010f565b61010f6101e5366004610926565b61038a565b6101986101933660046109c2565b61021f7f000000000000000000000000000000000000000000000000000000000000001281565b60405160ff9091168152602001610119565b61010f61023f366004610926565b60016020526000908152604090205481565b604080517f464c542d4c000000000000000000000000000000000000000000000000000000602082015281519082019091527f00000000000000000000000000000000000000000000000000000000000000058152610178565b6101986102b9366004610998565b610485565b61010f6102cc3660046109fe565b600092915050565b61010f7f0000000000000000000000000000000000000000000000000000000067afabe881565b6103227f000000000000000000000000236501327e701692a281934230af0b6be8df335381565b6040516001600160a01b039091168152602001610119565b60405162461bcd60e51b815260206004820152601560248201527f556e737570706f72746564206f7065726174696f6e000000000000000000000060448201526000906064015b60405180910390fd5b60007f0000000000000000000000000000000000000000000000000000000067afabe842116103bb57506000919050565b6001600160a01b0382166000908152602081815260408083205460019092528220547f0000000000000000000000000000000000000000000000000000000001e13380929061040a9083610a47565b905060006104387f0000000000000000000000000000000000000000000000000000000067afabe842610a47565b905060008482106104545761044d8385610a47565b905061047b565b60006104608686610a5a565b90508361046d8285610a7c565b6104779190610a47565b9150505b9695505050505050565b60006001600160a01b038316156105045760405162461bcd60e51b815260206004820152602960248201527f5472616e7366657220616c6c6f776564206f6e6c7920746f20746865207a657260448201527f6f206164647265737300000000000000000000000000000000000000000000006064820152608401610381565b3361050f8184610568565b836001600160a01b0316816001600160a01b03167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8560405161055491815260200190565b60405180910390a360019150505b92915050565b60006105738361038a565b9050600081116105c55760405162461bcd60e51b815260206004820152601d60248201527f4e6f7420656e6f756768207468652072656c6561736520616d6f756e740000006044820152606401610381565b8115610620578082111561061b5760405162461bcd60e51b815260206004820152601d60248201527f4e6f7420656e6f756768207468652072656c6561736520616d6f756e740000006044820152606401610381565b610624565b8091505b6001600160a01b0383166000908152600160205260408120805484929061064c908490610a47565b9250508190555081600260008282546106659190610a47565b9091555061069f90506001600160a01b037f000000000000000000000000236501327e701692a281934230af0b6be8df33531684846106a4565b505050565b604080516001600160a01b03848116602483015260448083018590528351808403909101815260649092019092526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fa9059cbb0000000000000000000000000000000000000000000000000000000017905261069f9185919060009061073090841683610797565b905080516000141580156107555750808060200190518101906107539190610a93565b155b1561069f576040517f5274afe70000000000000000000000000000000000000000000000000000000081526001600160a01b0384166004820152602401610381565b60606107a5838360006107ac565b9392505050565b6060814710156107ea576040517fcd786059000000000000000000000000000000000000000000000000000000008152306004820152602401610381565b600080856001600160a01b031684866040516108069190610ab5565b60006040518083038185875af1925050503d8060008114610843576040519150601f19603f3d011682016040523d82523d6000602084013e610848565b606091505b509150915061047b86838360608261086857610863826108c8565b6107a5565b815115801561087f57506001600160a01b0384163b155b156108c1576040517f9996b3150000000000000000000000000000000000000000000000000000000081526001600160a01b0385166004820152602401610381565b50806107a5565b8051156108d85780518082602001fd5b6040517f1425ea4200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80356001600160a01b038116811461092157600080fd5b919050565b60006020828403121561093857600080fd5b6107a58261090a565b60005b8381101561095c578181015183820152602001610944565b50506000910152565b6020815260008251806020840152610984816040850160208701610941565b601f01601f19169190910160400192915050565b600080604083850312156109ab57600080fd5b6109b48361090a565b946020939093013593505050565b6000806000606084860312156109d757600080fd5b6109e08461090a565b92506109ee6020850161090a565b9150604084013590509250925092565b60008060408385031215610a1157600080fd5b610a1a8361090a565b9150610a286020840161090a565b90509250929050565b634e487b7160e01b600052601160045260246000fd5b8181038181111561056257610562610a31565b600082610a7757634e487b7160e01b600052601260045260246000fd5b500490565b808202811582820484141761056257610562610a31565b600060208284031215610aa557600080fd5b815180151581146107a557600080fd5b60008251610ac7818460208701610941565b919091019291505056fea2646970667358221220aa9a251bde32306273cb5f6045040ac4b74b767bd02205c60c6003c5346ac34c64736f6c63430008140033", + "codeHash": "0xc10e7caa80b2af0d4faa10cd68f5a88dc5bbcf9d4f056677c3d259c8f31040e9", "nonce": 1, "storage": { "0x0000000000000000000000000000000000000000000000000000000000000002": "0x0000000000000000000000000000000000000000007b74591c97f086c1057bee", 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/live/supply.go b/eth/tracers/live/supply.go index bae7445cb4..ad3b9cbae3 100644 --- a/eth/tracers/live/supply.go +++ b/eth/tracers/live/supply.go @@ -199,8 +199,7 @@ func (s *supplyTracer) onBalanceChange(a common.Address, prevBalance, newBalance // NOTE: don't handle "BalanceIncreaseGenesisBalance" because it is handled in OnGenesisBlock switch reason { - case tracing.BalanceIncreaseRewardMineUncle: - case tracing.BalanceIncreaseRewardMineBlock: + case tracing.BalanceIncreaseRewardMineBlock, tracing.BalanceIncreaseRewardMineUncle: s.delta.Issuance.Reward.Add(s.delta.Issuance.Reward, diff) case tracing.BalanceIncreaseWithdrawal: s.delta.Issuance.Withdrawals.Add(s.delta.Issuance.Withdrawals, diff) 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..362125dd63 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 } @@ -819,7 +829,15 @@ func DoEstimateGas(ctx context.Context, b Backend, args TransactionArgs, blockNr if state == nil || err != nil { return 0, err } - if err := overrides.Apply(state, nil); err != nil { + blockCtx := core.NewEVMBlockContext(header, NewChainContext(ctx, b), nil) + if blockOverrides != nil { + if err := blockOverrides.Apply(&blockCtx); err != nil { + return 0, err + } + } + rules := b.ChainConfig().Rules(blockCtx.BlockNumber, blockCtx.Random != nil, blockCtx.Time) + precompiles := vm.ActivePrecompiledContracts(rules) + if err := overrides.Apply(state, precompiles); err != nil { return 0, err } // Construct the gas estimator option from the user input diff --git a/internal/ethapi/api_test.go b/internal/ethapi/api_test.go index de6d1d5e06..0a6c721405 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), @@ -3726,3 +3725,45 @@ func TestCreateAccessListWithStateOverrides(t *testing.T) { }} require.Equal(t, expected, result.Accesslist) } + +func TestEstimateGasWithMovePrecompile(t *testing.T) { + t.Parallel() + // Initialize test accounts + var ( + accounts = newAccounts(2) + genesis = &core.Genesis{ + Config: params.MergedTestChainConfig, + Alloc: types.GenesisAlloc{ + accounts[0].addr: {Balance: big.NewInt(params.Ether)}, + }, + } + ) + backend := newTestBackend(t, 1, genesis, beacon.New(ethash.NewFaker()), func(i int, b *core.BlockGen) { + b.SetPoS() + }) + api := NewBlockChainAPI(backend) + // Move SHA256 precompile (0x2) to a new address (0x100) + // and estimate gas for calling the moved precompile. + var ( + sha256Addr = common.BytesToAddress([]byte{0x2}) + newSha256Addr = common.BytesToAddress([]byte{0x10, 0}) + sha256Input = hexutil.Bytes([]byte("hello")) + args = TransactionArgs{ + From: &accounts[0].addr, + To: &newSha256Addr, + Data: &sha256Input, + } + overrides = &override.StateOverride{ + sha256Addr: override.OverrideAccount{ + MovePrecompileTo: &newSha256Addr, + }, + } + ) + gas, err := api.EstimateGas(context.Background(), args, nil, overrides, nil) + if err != nil { + t.Fatalf("EstimateGas failed: %v", err) + } + if gas != 21366 { + t.Fatalf("mismatched gas: %d, want 21366", gas) + } +} diff --git a/internal/ethapi/override/override_test.go b/internal/ethapi/override/override_test.go index 02a17c1331..41b4f2c253 100644 --- a/internal/ethapi/override/override_test.go +++ b/internal/ethapi/override/override_test.go @@ -31,6 +31,10 @@ import ( type precompileContract struct{} +func (p *precompileContract) Name() string { + panic("implement me") +} + func (p *precompileContract) RequiredGas(input []byte) uint64 { return 0 } func (p *precompileContract) Run(input []byte) ([]byte, error) { return nil, nil } 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/rpc/websocket_test.go b/rpc/websocket_test.go index a8d8624900..3b7d5a9da0 100644 --- a/rpc/websocket_test.go +++ b/rpc/websocket_test.go @@ -121,56 +121,49 @@ func TestWebsocketLargeRead(t *testing.T) { srv = newTestServer() httpsrv = httptest.NewServer(srv.WebsocketHandler([]string{"*"})) wsURL = "ws:" + strings.TrimPrefix(httpsrv.URL, "http:") + buffer = 64 ) defer srv.Stop() defer httpsrv.Close() - testLimit := func(limit *int64) { - opts := []ClientOption{} - expLimit := int64(wsDefaultReadLimit) - if limit != nil && *limit >= 0 { - opts = append(opts, WithWebsocketMessageSizeLimit(*limit)) - if *limit > 0 { - expLimit = *limit // 0 means infinite + for _, tt := range []struct { + size int + limit int + err bool + }{ + {200, 200, false}, // Small, successful request and limit + {2048, 1024, true}, // Normal, failed request + {wsDefaultReadLimit + buffer, 0, false}, // Large, successful request, infinite limit + } { + func() { + if tt.limit != 0 { + // Some buffer is added to the limit to account for JSON encoding. It's + // skipped when the limit is zero since the intention is for the limit + // to be infinite. + tt.limit += buffer } - } - client, err := DialOptions(context.Background(), wsURL, opts...) - if err != nil { - t.Fatalf("can't dial: %v", err) - } - defer client.Close() - // Remove some bytes for json encoding overhead. - underLimit := int(expLimit - 128) - overLimit := expLimit + 1 - if expLimit == wsDefaultReadLimit { - // No point trying the full 32MB in tests. Just sanity-check that - // it's not obviously limited. - underLimit = 1024 - overLimit = -1 - } - var res string - // Check under limit - if err = client.Call(&res, "test_repeat", "A", underLimit); err != nil { - t.Fatalf("unexpected error with limit %d: %v", expLimit, err) - } - if len(res) != underLimit || strings.Count(res, "A") != underLimit { - t.Fatal("incorrect data") - } - // Check over limit - if overLimit > 0 { - err = client.Call(&res, "test_repeat", "A", expLimit+1) - if err == nil || err != websocket.ErrReadLimit { - t.Fatalf("wrong error with limit %d: %v expecting %v", expLimit, err, websocket.ErrReadLimit) + opts := []ClientOption{WithWebsocketMessageSizeLimit(int64(tt.limit))} + client, err := DialOptions(context.Background(), wsURL, opts...) + if err != nil { + t.Fatalf("failed to dial test server: %v", err) } - } - } - ptr := func(v int64) *int64 { return &v } + defer client.Close() - testLimit(ptr(-1)) // Should be ignored (use default) - testLimit(ptr(0)) // Should be ignored (use default) - testLimit(nil) // Should be ignored (use default) - testLimit(ptr(200)) - testLimit(ptr(wsDefaultReadLimit * 2)) + var res string + err = client.Call(&res, "test_repeat", "A", tt.size) + if tt.err && err == nil { + t.Fatalf("expected error, got none") + } + if !tt.err { + if err != nil { + t.Fatalf("unexpected error with limit %d: %v", tt.limit, err) + } + if strings.Count(res, "A") != tt.size { + t.Fatal("incorrect data") + } + } + }() + } } func TestWebsocketPeerInfo(t *testing.T) { 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..b1e2e75784 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,25 +306,26 @@ 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) } if frozen != 0 { - // 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) - err := db.freezer.Reset() - if err != nil { + batch := db.diskdb.NewBatch() + rawdb.DeleteStateHistoryIndexMetadata(batch) + rawdb.DeleteStateHistoryIndex(batch) + if err := batch.Write(); err != nil { + log.Crit("Failed to purge state history index", "err", err) + } + if err := db.stateFreezer.Reset(); err != nil { log.Crit("Failed to reset state histories", "err", err) } log.Info("Truncated extraneous state history") @@ -331,7 +334,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 +510,15 @@ 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 { - // TODO(rjl493456442) would be better to group them into a batch. - // + if db.stateFreezer != nil { // Purge all state history indexing data first - rawdb.DeleteStateHistoryIndexMetadata(db.diskdb) - rawdb.DeleteStateHistoryIndex(db.diskdb) - if err := db.freezer.Reset(); err != nil { + batch.Reset() + rawdb.DeleteStateHistoryIndexMetadata(batch) + rawdb.DeleteStateHistoryIndex(batch) + if err := batch.Write(); err != nil { + return err + } + if err := db.stateFreezer.Reset(); err != nil { return err } } @@ -529,9 +534,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 +556,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 +569,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 +590,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 +618,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 +651,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 +709,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 +722,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..f1248b02bd 100644 --- a/triedb/pathdb/disklayer.go +++ b/triedb/pathdb/disklayer.go @@ -323,6 +323,69 @@ func (dl *diskLayer) update(root common.Hash, id uint64, block uint64, nodes *no return newDiffLayer(dl, root, id, block, nodes, states) } +// writeStateHistory stores the state history and indexes if indexing is +// permitted. +// +// What's more, this function also returns a flag indicating whether the +// buffer flushing is required, ensuring the persistent state ID is always +// greater than or equal to the first history ID. +func (dl *diskLayer) writeStateHistory(diff *diffLayer) (bool, error) { + // Short circuit if state history is not permitted + if dl.db.stateFreezer == nil { + return false, nil + } + // Bail out with an error if writing the state history fails. + // This can happen, for example, if the device is full. + err := writeStateHistory(dl.db.stateFreezer, diff) + if err != nil { + return false, err + } + // Notify the state history indexer for newly created history + if dl.db.stateIndexer != nil { + if err := dl.db.stateIndexer.extend(diff.stateID()); err != nil { + return false, err + } + } + // Determine if the persisted history object has exceeded the + // configured limitation. + limit := dl.db.config.StateHistory + if limit == 0 { + return false, nil + } + tail, err := dl.db.stateFreezer.Tail() + if err != nil { + return false, err + } // firstID = tail+1 + + // length = diff.stateID()-firstID+1 = diff.stateID()-tail + if diff.stateID()-tail <= limit { + return false, nil + } + newFirst := diff.stateID() - limit + 1 // the id of first history **after truncation** + + // In a rare case where the ID of the first history object (after tail + // truncation) exceeds the persisted state ID, we must take corrective + // steps: + // + // - Skip tail truncation temporarily, avoid the scenario that associated + // history of persistent state is removed + // + // - Force a commit of the cached dirty states into persistent state + // + // These measures ensure the persisted state ID always remains greater + // than or equal to the first history ID. + if persistentID := rawdb.ReadPersistentStateID(dl.db.diskdb); persistentID < newFirst { + log.Debug("Skip tail truncation", "persistentID", persistentID, "tailID", tail+1, "headID", diff.stateID(), "limit", limit) + return true, nil + } + pruned, err := truncateFromTail(dl.db.diskdb, dl.db.stateFreezer, newFirst-1) + if err != nil { + return false, err + } + log.Debug("Pruned state history", "items", pruned, "tailid", newFirst) + return false, nil +} + // commit merges the given bottom-most diff layer into the node buffer // and returns a newly constructed disk layer. Note the current disk // layer must be tagged as stale first to prevent re-access. @@ -333,34 +396,9 @@ func (dl *diskLayer) commit(bottom *diffLayer, force bool) (*diskLayer, error) { // Construct and store the state history first. If crash happens after storing // the state history but without flushing the corresponding states(journal), // the stored state history will be truncated from head in the next restart. - var ( - overflow bool - oldest uint64 - ) - if dl.db.freezer != 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) - 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() - if err != nil { - return nil, err - } - limit := dl.db.config.StateHistory - if limit != 0 && bottom.stateID()-tail > limit { - overflow = true - 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 { - return nil, err - } - } + flush, err := dl.writeStateHistory(bottom) + if err != nil { + return nil, err } // Mark the diskLayer as stale before applying any mutations on top. dl.stale = true @@ -373,21 +411,13 @@ func (dl *diskLayer) commit(bottom *diffLayer, force bool) (*diskLayer, error) { } rawdb.WriteStateID(dl.db.diskdb, bottom.rootHash(), bottom.stateID()) - // In a unique scenario where the ID of the oldest history object (after tail - // truncation) surpasses the persisted state ID, we take the necessary action - // of forcibly committing the cached dirty states to ensure that the persisted - // state ID remains higher. - persistedID := rawdb.ReadPersistentStateID(dl.db.diskdb) - if !force && persistedID < oldest { - force = true - } // Merge the trie nodes and flat states of the bottom-most diff layer into the // buffer as the combined layer. combined := dl.buffer.commit(bottom.nodes, bottom.states.stateSet) // Terminate the background state snapshot generation before mutating the // persistent state. - if combined.full() || force { + if combined.full() || force || flush { // Wait until the previous frozen buffer is fully flushed if dl.frozen != nil { if err := dl.frozen.waitFlush(); err != nil { @@ -418,7 +448,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. @@ -431,8 +461,8 @@ func (dl *diskLayer) commit(bottom *diffLayer, force bool) (*diskLayer, error) { } }) // Block until the frozen buffer is fully flushed out if the async flushing - // is not allowed, or if the oldest history surpasses the persisted state ID. - if dl.db.config.NoAsyncFlush || persistedID < oldest { + // is not allowed. + if dl.db.config.NoAsyncFlush { if err := dl.frozen.waitFlush(); err != nil { return nil, err } @@ -445,20 +475,11 @@ func (dl *diskLayer) commit(bottom *diffLayer, force bool) (*diskLayer, error) { if dl.generator != nil { ndl.setGenerator(dl.generator) } - // 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) - if err != nil { - return nil, err - } - log.Debug("Pruned state history", "items", pruned, "tailid", oldest) - } return ndl, nil } // 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 +505,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..127459b47c 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. @@ -598,14 +598,17 @@ func checkVersion(disk ethdb.KeyValueStore) { if err == nil && m.Version == stateIndexVersion { return } - // TODO(rjl493456442) would be better to group them into a batch. - rawdb.DeleteStateHistoryIndexMetadata(disk) - rawdb.DeleteStateHistoryIndex(disk) - version := "unknown" if err == nil { version = fmt.Sprintf("%d", m.Version) } + + batch := disk.NewBatch() + rawdb.DeleteStateHistoryIndexMetadata(batch) + rawdb.DeleteStateHistoryIndex(batch) + if err := batch.Write(); err != nil { + log.Crit("Failed to purge state history index", "err", err) + } log.Info("Cleaned up obsolete state history index", "version", version, "want", stateIndexVersion) } 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 }